Compare commits

..

8 Commits

Author SHA1 Message Date
Josh Hawkins
42fdadecd9 clarify audio transcription docs 2025-11-23 12:35:35 -06:00
Josh Hawkins
bf4f63e50e make live view settings drawer scrollable 2025-11-23 12:25:23 -06:00
Josh Hawkins
9242997079 spacing tweaks 2025-11-23 12:25:00 -06:00
Josh Hawkins
c5e08c7bcf fix wording in reference config 2025-11-23 12:22:27 -06:00
icidi
2d8b6c8301
fix typo (#20969)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
2025-11-23 08:43:15 -07:00
Blake Blackshear
84c3f98a09
clarify trademark and license interaction (#21019) 2025-11-23 08:42:48 -07:00
Jakub Sojka
c87f89fcc1
Chore/update yq to 4.48.2 (#20967)
* chore: update yq from 4.33.3 to 4.48.2

* fix: update yq v4 syntax for Frigate config upload command

---------

Co-authored-by: Jakub Sojka <jakub.sojka@mallgroup.com>
2025-11-23 08:41:44 -07:00
Josh Hawkins
815303922d
Miscellaneous Fixes (#21005)
* update live view docs

* use swr as single source of truth for searchDetail

rather than maintaining a separate state, derive the selected item from swr cache. fixes websocket sync when regenerating descriptions or fetching transcriptions

* fix key warning in console

* don't try to fetch event from review item for audio events

* update audio transcription toast wording

* Add a community supported badge to specific detectors in the info summaries to better separate

* Make object classification publish to tracked object update and add examples for state classification

* Add item to advanced docs about tensorflow limiting

* Don't show submission for in progress objects

* fix for ios not reporting video dimensions on initial metadata load

in testing, polling with requestAnimationFrame finds the dimensions within 2 frames

* Catch jetson nvidia device tree

---------

Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
2025-11-23 08:40:25 -07:00
36 changed files with 501 additions and 340 deletions

View File

@ -1,6 +1,6 @@
The MIT License The MIT License
Copyright (c) 2020 Blake Blackshear Copyright (c) 2025 Frigate LLC (Frigate™)
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -1,8 +1,10 @@
<p align="center"> <p align="center">
<img align="center" alt="logo" src="docs/static/img/frigate.png"> <img align="center" alt="logo" src="docs/static/img/branding/frigate.png">
</p> </p>
# Frigate - NVR With Realtime Object Detection for IP Cameras # Frigate NVR™ - Realtime Object Detection for IP Cameras
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
<a href="https://hosted.weblate.org/engage/frigate-nvr/"> <a href="https://hosted.weblate.org/engage/frigate-nvr/">
<img src="https://hosted.weblate.org/widget/frigate-nvr/language-badge.svg" alt="Translation status" /> <img src="https://hosted.weblate.org/widget/frigate-nvr/language-badge.svg" alt="Translation status" />
@ -33,6 +35,15 @@ View the documentation at https://docs.frigate.video
If you would like to make a donation to support development, please use [Github Sponsors](https://github.com/sponsors/blakeblackshear). If you would like to make a donation to support development, please use [Github Sponsors](https://github.com/sponsors/blakeblackshear).
## License
This project is licensed under the **MIT License**.
- **Code:** The source code, configuration files, and documentation in this repository are available under the [MIT License](LICENSE). You are free to use, modify, and distribute the code as long as you include the original copyright notice.
- **Trademarks:** The "Frigate" name, the "Frigate NVR" brand, and the Frigate logo are **trademarks of Frigate LLC** and are **not** covered by the MIT License.
Please see our [Trademark Policy](TRADEMARK.md) for details on acceptable use of our brand assets.
## Screenshots ## Screenshots
### Live dashboard ### Live dashboard
@ -66,3 +77,7 @@ We use [Weblate](https://hosted.weblate.org/projects/frigate-nvr/) to support la
<a href="https://hosted.weblate.org/engage/frigate-nvr/"> <a href="https://hosted.weblate.org/engage/frigate-nvr/">
<img src="https://hosted.weblate.org/widget/frigate-nvr/multi-auto.svg" alt="Translation status" /> <img src="https://hosted.weblate.org/widget/frigate-nvr/multi-auto.svg" alt="Translation status" />
</a> </a>
---
**Copyright © 2025 Frigate LLC.**

58
TRADEMARK.md Normal file
View File

@ -0,0 +1,58 @@
# Trademark Policy
**Last Updated:** November 2025
This document outlines the policy regarding the use of the trademarks associated with the Frigate NVR project.
## 1. Our Trademarks
The following terms and visual assets are trademarks (the "Marks") of **Frigate LLC**:
- **Frigate™**
- **Frigate NVR™**
- **Frigate+™**
- **The Frigate Logo**
**Note on Common Law Rights:**
Frigate LLC asserts all common law rights in these Marks. The absence of a federal registration symbol (®) does not constitute a waiver of our intellectual property rights.
## 2. Interaction with the MIT License
The software in this repository is licensed under the [MIT License](LICENSE).
**Crucial Distinction:**
- The **Code** is free to use, modify, and distribute under the MIT terms.
- The **Brand (Trademarks)** is **NOT** licensed under MIT.
You may not use the Marks in any way that is not explicitly permitted by this policy or by written agreement with Frigate LLC.
## 3. Acceptable Use
You may use the Marks without prior written permission in the following specific contexts:
- **Referential Use:** To truthfully refer to the software (e.g., _"I use Frigate NVR for my home security"_).
- **Compatibility:** To indicate that your product or project works with the software (e.g., _"MyPlugin for Frigate NVR"_ or _"Compatible with Frigate"_).
- **Commentary:** In news articles, blog posts, or tutorials discussing the software.
## 4. Prohibited Use
You may **NOT** use the Marks in the following ways:
- **Commercial Products:** You may not use "Frigate" in the name of a commercial product, service, or app (e.g., selling an app named _"Frigate Viewer"_ is prohibited).
- **Implying Affiliation:** You may not use the Marks in a way that suggests your project is official, sponsored by, or endorsed by Frigate LLC.
- **Confusing Forks:** If you fork this repository to create a derivative work, you **must** remove the Frigate logo and rename your project to avoid user confusion. You cannot distribute a modified version of the software under the name "Frigate".
- **Domain Names:** You may not register domain names containing "Frigate" that are likely to confuse users (e.g., `frigate-official-support.com`).
## 5. The Logo
The Frigate logo (the bird icon) is a visual trademark.
- You generally **cannot** use the logo on your own website or product packaging without permission.
- If you are building a dashboard or integration that interfaces with Frigate, you may use the logo only to represent the Frigate node/service, provided it does not imply you _are_ Frigate.
## 6. Questions & Permissions
If you are unsure if your intended use violates this policy, or if you wish to request a specific license to use the Marks (e.g., for a partnership), please contact us at:
**help@frigate.video**

View File

@ -145,6 +145,6 @@ rm -rf /var/lib/apt/lists/*
# Install yq, for frigate-prepare and go2rtc echo source # Install yq, for frigate-prepare and go2rtc echo source
curl -fsSL \ curl -fsSL \
"https://github.com/mikefarah/yq/releases/download/v4.33.3/yq_linux_$(dpkg --print-architecture)" \ "https://github.com/mikefarah/yq/releases/download/v4.48.2/yq_linux_$(dpkg --print-architecture)" \
--output /usr/local/bin/yq --output /usr/local/bin/yq
chmod +x /usr/local/bin/yq chmod +x /usr/local/bin/yq

View File

@ -258,7 +258,7 @@ curl -X POST http://frigate_host:5000/api/config/save -d @config.json
if you'd like you can use your yaml config directly by using [`yq`](https://github.com/mikefarah/yq) to convert it to json: if you'd like you can use your yaml config directly by using [`yq`](https://github.com/mikefarah/yq) to convert it to json:
```bash ```bash
yq r -j config.yml | curl -X POST http://frigate_host:5000/api/config/save -d @- yq -o=json '.' config.yaml | curl -X POST 'http://frigate_host:5000/api/config/save?save_option=saveonly' --data-binary @-
``` ```
### Via Command Line ### Via Command Line

View File

@ -144,4 +144,10 @@ In order to use transcription and translation for past events, you must enable a
The transcribed/translated speech will appear in the description box in the Tracked Object Details pane. If Semantic Search is enabled, embeddings are generated for the transcription text and are fully searchable using the description search type. The transcribed/translated speech will appear in the description box in the Tracked Object Details pane. If Semantic Search is enabled, embeddings are generated for the transcription text and are fully searchable using the description search type.
Recorded `speech` events will always use a `whisper` model, regardless of the `model_size` config setting. Without a GPU, generating transcriptions for longer `speech` events may take a fair amount of time, so be patient. :::note
Only one `speech` event may be transcribed at a time. Frigate does not automatically transcribe `speech` events or implement a queue for long-running transcription model inference.
:::
Recorded `speech` events will always use a `whisper` model, regardless of the `model_size` config setting. Without a supported Nvidia GPU, generating transcriptions for longer `speech` events may take a fair amount of time, so be patient.

View File

@ -246,7 +246,7 @@ birdseye:
# Optional: ffmpeg configuration # Optional: ffmpeg configuration
# More information about presets at https://docs.frigate.video/configuration/ffmpeg_presets # More information about presets at https://docs.frigate.video/configuration/ffmpeg_presets
ffmpeg: ffmpeg:
# Optional: ffmpeg binry path (default: shown below) # Optional: ffmpeg binary path (default: shown below)
# can also be set to `7.0` or `5.0` to specify one of the included versions # can also be set to `7.0` or `5.0` to specify one of the included versions
# or can be set to any path that holds `bin/ffmpeg` & `bin/ffprobe` # or can be set to any path that holds `bin/ffmpeg` & `bin/ffprobe`
path: "default" path: "default"
@ -700,11 +700,11 @@ genai:
# Optional: Configuration for audio transcription # Optional: Configuration for audio transcription
# NOTE: only the enabled option can be overridden at the camera level # NOTE: only the enabled option can be overridden at the camera level
audio_transcription: audio_transcription:
# Optional: Enable license plate recognition (default: shown below) # Optional: Enable live and speech event audio transcription (default: shown below)
enabled: False enabled: False
# Optional: The device to run the models on (default: shown below) # Optional: The device to run the models on for live transcription. (default: shown below)
device: CPU device: CPU
# Optional: Set the model size used for transcription. (default: shown below) # Optional: Set the model size used for live transcription. (default: shown below)
model_size: small model_size: small
# Optional: Set the language used for transcription translation. (default: shown below) # Optional: Set the language used for transcription translation. (default: shown below)
# List of language codes: https://github.com/openai/whisper/blob/main/whisper/tokenizer.py#L10 # List of language codes: https://github.com/openai/whisper/blob/main/whisper/tokenizer.py#L10

View File

@ -10,7 +10,7 @@ const config: Config = {
baseUrl: "/", baseUrl: "/",
onBrokenLinks: "throw", onBrokenLinks: "throw",
onBrokenMarkdownLinks: "warn", onBrokenMarkdownLinks: "warn",
favicon: "img/favicon.ico", favicon: "img/branding/favicon.ico",
organizationName: "blakeblackshear", organizationName: "blakeblackshear",
projectName: "frigate", projectName: "frigate",
themes: [ themes: [
@ -116,8 +116,8 @@ const config: Config = {
title: "Frigate", title: "Frigate",
logo: { logo: {
alt: "Frigate", alt: "Frigate",
src: "img/logo.svg", src: "img/branding/logo.svg",
srcDark: "img/logo-dark.svg", srcDark: "img/branding/logo-dark.svg",
}, },
items: [ items: [
{ {
@ -170,7 +170,7 @@ const config: Config = {
], ],
}, },
], ],
copyright: `Copyright © ${new Date().getFullYear()} Blake Blackshear`, copyright: `Copyright © ${new Date().getFullYear()} Frigate LLC`,
}, },
}, },
plugins: [ plugins: [

30
docs/static/img/branding/LICENSE.md vendored Normal file
View File

@ -0,0 +1,30 @@
# COPYRIGHT AND TRADEMARK NOTICE
The images, logos, and icons contained in this directory (the "Brand Assets") are
proprietary to Frigate LLC and are NOT covered by the MIT License governing the
rest of this repository.
1. TRADEMARK STATUS
The "Frigate" name and the accompanying logo are common law trademarks™ of
Frigate LLC. Frigate LLC reserves all rights to these marks.
2. LIMITED PERMISSION FOR USE
Permission is hereby granted to display these Brand Assets strictly for the
following purposes:
a. To execute the software interface on a local machine.
b. To identify the software in documentation or reviews (nominative use).
3. RESTRICTIONS
You may NOT:
a. Use these Brand Assets to represent a derivative work (fork) as an official
product of Frigate LLC.
b. Use these Brand Assets in a way that implies endorsement, sponsorship, or
commercial affiliation with Frigate LLC.
c. Modify or alter the Brand Assets.
If you fork this repository with the intent to distribute a modified or competing
version of the software, you must replace these Brand Assets with your own
original content.
ALL RIGHTS RESERVED.
Copyright (c) 2025 Frigate LLC.

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 936 B

After

Width:  |  Height:  |  Size: 936 B

View File

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 933 B

View File

@ -130,8 +130,13 @@ def get_soc_type() -> Optional[str]:
"""Get the SoC type from device tree.""" """Get the SoC type from device tree."""
try: try:
with open("/proc/device-tree/compatible") as file: with open("/proc/device-tree/compatible") as file:
soc = file.read().split(",")[-1].strip("\x00") content = file.read()
return soc
# Check for Jetson devices
if "nvidia" in content:
return None
return content.split(",")[-1].strip("\x00")
except FileNotFoundError: except FileNotFoundError:
logger.debug("Could not determine SoC type from device tree") logger.debug("Could not determine SoC type from device tree")
return None return None

View File

@ -0,0 +1,33 @@
# COPYRIGHT AND TRADEMARK NOTICE
The images, logos, and icons contained in this directory (the "Brand Assets") are
proprietary to Frigate LLC and are NOT covered by the MIT License governing the
rest of this repository.
1. TRADEMARK STATUS
The "Frigate" name and the accompanying logo are common law trademarks™ of
Frigate LLC. Frigate LLC reserves all rights to these marks.
2. LIMITED PERMISSION FOR USE
Permission is hereby granted to display these Brand Assets strictly for the
following purposes:
a. To execute the software interface on a local machine.
b. To identify the software in documentation or reviews (nominative use).
3. RESTRICTIONS
You may NOT:
a. Use these Brand Assets to represent a derivative work (fork) as an official
product of Frigate LLC.
b. Use these Brand Assets in a way that implies endorsement, sponsorship, or
commercial affiliation with Frigate LLC.
c. Modify or alter the Brand Assets.
If you fork this repository with the intent to distribute a modified or competing
version of the software, you must replace these Brand Assets with your own
original content.
For full usage guidelines, strictly see the TRADEMARK.md file in the
repository root.
ALL RIGHTS RESERVED.
Copyright (c) 2025 Frigate LLC.

View File

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

Before

Width:  |  Height:  |  Size: 558 B

After

Width:  |  Height:  |  Size: 558 B

View File

Before

Width:  |  Height:  |  Size: 800 B

After

Width:  |  Height:  |  Size: 800 B

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -2,29 +2,29 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="/images/favicon.ico" /> <link rel="icon" href="/images/branding/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Frigate</title> <title>Frigate</title>
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="180x180" sizes="180x180"
href="/images/apple-touch-icon.png" href="/images/branding/apple-touch-icon.png"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
sizes="32x32" sizes="32x32"
href="/images/favicon-32x32.png" href="/images/branding/favicon-32x32.png"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
sizes="16x16" sizes="16x16"
href="/images/favicon-16x16.png" href="/images/branding/favicon-16x16.png"
/> />
<link rel="icon" type="image/svg+xml" href="/images/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/images/branding/favicon.svg" />
<link rel="manifest" href="/site.webmanifest" crossorigin="use-credentials" /> <link rel="manifest" href="/site.webmanifest" crossorigin="use-credentials" />
<link rel="mask-icon" href="/images/favicon.svg" color="#3b82f7" /> <link rel="mask-icon" href="/images/branding/favicon.svg" color="#3b82f7" />
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" /> <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)" /> <meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)" />
</head> </head>

View File

@ -2,29 +2,29 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" href="/images/favicon.ico" /> <link rel="icon" href="/images/branding/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Frigate</title> <title>Frigate</title>
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="180x180" sizes="180x180"
href="/images/apple-touch-icon.png" href="/images/branding/apple-touch-icon.png"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
sizes="32x32" sizes="32x32"
href="/images/favicon-32x32.png" href="/images/branding/favicon-32x32.png"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
sizes="16x16" sizes="16x16"
href="/images/favicon-16x16.png" href="/images/branding/favicon-16x16.png"
/> />
<link rel="icon" type="image/svg+xml" href="/images/favicon.svg" /> <link rel="icon" type="image/svg+xml" href="/images/branding/favicon.svg" />
<link rel="manifest" href="/site.webmanifest" crossorigin="use-credentials" /> <link rel="manifest" href="/site.webmanifest" crossorigin="use-credentials" />
<link rel="mask-icon" href="/images/favicon.svg" color="#3b82f7" /> <link rel="mask-icon" href="/images/branding/favicon.svg" color="#3b82f7" />
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" /> <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)" /> <meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)" />
</head> </head>

View File

@ -1376,8 +1376,9 @@ function FrigateCameraFeatures({
title={t("cameraSettings.title", { camera })} title={t("cameraSettings.title", { camera })}
/> />
</DrawerTrigger> </DrawerTrigger>
<DrawerContent className="rounded-2xl px-2 py-4"> <DrawerContent className="max-h-[75dvh] overflow-hidden rounded-2xl">
<div className="mt-2 flex flex-col gap-2"> <div className="scrollbar-container mt-2 flex h-auto flex-col gap-2 overflow-y-auto px-2 py-4">
<>
{isAdmin && ( {isAdmin && (
<> <>
<FilterSwitch <FilterSwitch
@ -1425,7 +1426,9 @@ function FrigateCameraFeatures({
disabled={audioState == "OFF"} disabled={audioState == "OFF"}
isChecked={transcriptionState == "ON"} isChecked={transcriptionState == "ON"}
onCheckedChange={() => onCheckedChange={() =>
sendTranscription(transcriptionState == "ON" ? "OFF" : "ON") sendTranscription(
transcriptionState == "ON" ? "OFF" : "ON",
)
} }
/> />
)} )}
@ -1440,7 +1443,6 @@ function FrigateCameraFeatures({
)} )}
</> </>
)} )}
</div>
<div className="mt-3 flex flex-col gap-5"> <div className="mt-3 flex flex-col gap-5">
{!isRestreamed && ( {!isRestreamed && (
@ -1482,7 +1484,8 @@ function FrigateCameraFeatures({
</div> </div>
</div> </div>
)} )}
{isRestreamed && Object.values(camera.live.streams).length > 0 && ( {isRestreamed &&
Object.values(camera.live.streams).length > 0 && (
<div className="mt-1 p-2"> <div className="mt-1 p-2">
<div className="mb-1 text-sm">{t("stream.title")}</div> <div className="mb-1 text-sm">{t("stream.title")}</div>
<Select <Select
@ -1526,7 +1529,9 @@ function FrigateCameraFeatures({
</div> </div>
)} )}
{preferredLiveMode != "jsmpeg" && !debug && isRestreamed && ( {preferredLiveMode != "jsmpeg" &&
!debug &&
isRestreamed && (
<div className="mt-1 flex flex-row items-center gap-1 text-sm text-muted-foreground"> <div className="mt-1 flex flex-row items-center gap-1 text-sm text-muted-foreground">
{supportsAudioOutput ? ( {supportsAudioOutput ? (
<> <>
@ -1555,7 +1560,9 @@ function FrigateCameraFeatures({
rel="noopener noreferrer" rel="noopener noreferrer"
className="inline" className="inline"
> >
{t("readTheDocumentation", { ns: "common" })} {t("readTheDocumentation", {
ns: "common",
})}
<LuExternalLink className="ml-2 inline-flex size-3" /> <LuExternalLink className="ml-2 inline-flex size-3" />
</Link> </Link>
</div> </div>
@ -1599,7 +1606,9 @@ function FrigateCameraFeatures({
rel="noopener noreferrer" rel="noopener noreferrer"
className="inline" className="inline"
> >
{t("readTheDocumentation", { ns: "common" })} {t("readTheDocumentation", {
ns: "common",
})}
<LuExternalLink className="ml-2 inline-flex size-3" /> <LuExternalLink className="ml-2 inline-flex size-3" />
</Link> </Link>
</div> </div>
@ -1613,7 +1622,9 @@ function FrigateCameraFeatures({
<div className="mt-2 flex flex-col items-center gap-3"> <div className="mt-2 flex flex-col items-center gap-3">
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2">
<IoIosWarning className="mr-1 size-8 text-danger" /> <IoIosWarning className="mr-1 size-8 text-danger" />
<p className="text-sm">{t("stream.lowBandwidth.tips")}</p> <p className="text-sm">
{t("stream.lowBandwidth.tips")}
</p>
</div> </div>
<Button <Button
className={`flex items-center gap-2.5 rounded-lg`} className={`flex items-center gap-2.5 rounded-lg`}
@ -1651,7 +1662,8 @@ function FrigateCameraFeatures({
onClick={handleEventButtonClick} onClick={handleEventButtonClick}
className={cn( className={cn(
"h-auto w-full whitespace-normal", "h-auto w-full whitespace-normal",
isRecording && "animate-pulse bg-red-500 hover:bg-red-600", isRecording &&
"animate-pulse bg-red-500 hover:bg-red-600",
)} )}
disabled={debug} disabled={debug}
> >
@ -1700,6 +1712,8 @@ function FrigateCameraFeatures({
/> />
</div> </div>
</div> </div>
</>
</div>
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
); );

View File

@ -784,7 +784,7 @@ export default function AuthenticationView({
return ( return (
<div className="flex size-full flex-col"> <div className="flex size-full flex-col">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none md:mr-3 md:mt-0"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none md:mr-3 md:mt-0">
{section === "users" && UsersSection} {section === "users" && UsersSection}
{section === "roles" && RolesSection} {section === "roles" && RolesSection}
{!section && ( {!section && (

View File

@ -65,7 +65,7 @@ export default function CameraManagementView({
closeButton closeButton
/> />
<div className="flex size-full flex-col md:flex-row"> <div className="flex size-full flex-col md:flex-row">
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none">
{viewMode === "settings" ? ( {viewMode === "settings" ? (
<> <>
<Heading as="h4" className="mb-2"> <Heading as="h4" className="mb-2">

View File

@ -298,7 +298,7 @@ export default function CameraReviewSettingsView({
<> <>
<div className="flex size-full flex-col md:flex-row"> <div className="flex size-full flex-col md:flex-row">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none">
<Heading as="h4" className="mb-2"> <Heading as="h4" className="mb-2">
{t("cameraReview.title")} {t("cameraReview.title")}
</Heading> </Heading>

View File

@ -244,7 +244,7 @@ export default function EnrichmentsSettingsView({
return ( return (
<div className="flex size-full flex-col md:flex-row"> <div className="flex size-full flex-col md:flex-row">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none">
<Heading as="h4" className="mb-2"> <Heading as="h4" className="mb-2">
{t("enrichments.title")} {t("enrichments.title")}
</Heading> </Heading>

View File

@ -211,7 +211,7 @@ export default function FrigatePlusSettingsView({
<> <>
<div className="flex size-full flex-col md:flex-row"> <div className="flex size-full flex-col md:flex-row">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none">
<Heading as="h4" className="mb-2"> <Heading as="h4" className="mb-2">
{t("frigatePlus.title")} {t("frigatePlus.title")}
</Heading> </Heading>

View File

@ -434,7 +434,7 @@ export default function MasksAndZonesView({
{cameraConfig && editingPolygons && ( {cameraConfig && editingPolygons && (
<div className="flex size-full flex-col md:flex-row"> <div className="flex size-full flex-col md:flex-row">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mr-3 md:mt-0 md:w-3/12"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mr-3 md:mt-0 md:w-3/12">
{editPane == "zone" && ( {editPane == "zone" && (
<ZoneEditPane <ZoneEditPane
polygons={editingPolygons} polygons={editingPolygons}

View File

@ -191,7 +191,7 @@ export default function MotionTunerView({
return ( return (
<div className="flex size-full flex-col md:flex-row"> <div className="flex size-full flex-col md:flex-row">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mr-3 md:mt-0 md:w-3/12"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mr-3 md:mt-0 md:w-3/12">
<Heading as="h4" className="mb-2"> <Heading as="h4" className="mb-2">
{t("motionDetectionTuner.title")} {t("motionDetectionTuner.title")}
</Heading> </Heading>

View File

@ -331,7 +331,7 @@ export default function NotificationView({
if (!("Notification" in window) || !window.isSecureContext) { if (!("Notification" in window) || !window.isSecureContext) {
return ( return (
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none">
<div className="grid w-full grid-cols-1 gap-4 md:grid-cols-2"> <div className="grid w-full grid-cols-1 gap-4 md:grid-cols-2">
<div className="col-span-1"> <div className="col-span-1">
<Heading as="h4" className="mb-2"> <Heading as="h4" className="mb-2">
@ -385,7 +385,7 @@ export default function NotificationView({
<> <>
<div className="flex size-full flex-col md:flex-row"> <div className="flex size-full flex-col md:flex-row">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto px-2 md:order-none"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto px-2 md:order-none">
<div <div
className={cn( className={cn(
isAdmin && "grid w-full grid-cols-1 gap-4 md:grid-cols-2", isAdmin && "grid w-full grid-cols-1 gap-4 md:grid-cols-2",

View File

@ -164,7 +164,7 @@ export default function ObjectSettingsView({
return ( return (
<div className="mt-1 flex size-full flex-col pb-2 md:flex-row"> <div className="mt-1 flex size-full flex-col pb-2 md:flex-row">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0 md:w-3/12"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto rounded-lg border-[1px] border-secondary-foreground bg-background_alt p-2 md:order-none md:mb-0 md:mr-2 md:mt-0 md:w-3/12">
<Heading as="h4" className="mb-2"> <Heading as="h4" className="mb-2">
{t("debug.title")} {t("debug.title")}
</Heading> </Heading>
@ -434,7 +434,7 @@ function ObjectList({ cameraConfig, objects }: ObjectListProps) {
{t("debug.objectShapeFilterDrawing.area")} {t("debug.objectShapeFilterDrawing.area")}
</p> </p>
{obj.area ? ( {obj.area ? (
<> <div className="text-end">
<div className="text-xs"> <div className="text-xs">
px: {obj.area.toString()} px: {obj.area.toString()}
</div> </div>
@ -448,7 +448,7 @@ function ObjectList({ cameraConfig, objects }: ObjectListProps) {
.toFixed(4) .toFixed(4)
.toString()} .toString()}
</div> </div>
</> </div>
) : ( ) : (
"-" "-"
)} )}

View File

@ -440,7 +440,7 @@ export default function TriggerView({
return ( return (
<div className="flex size-full flex-col md:flex-row"> <div className="flex size-full flex-col md:flex-row">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none md:mr-3 md:mt-0"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none md:mr-3 md:mt-0">
{!isSemanticSearchEnabled ? ( {!isSemanticSearchEnabled ? (
<div className="mb-5 flex flex-row items-center justify-between gap-2"> <div className="mb-5 flex flex-row items-center justify-between gap-2">
<div className="flex flex-col items-start"> <div className="flex flex-col items-start">

View File

@ -108,7 +108,7 @@ export default function UiSettingsView() {
<> <>
<div className="flex size-full flex-col md:flex-row"> <div className="flex size-full flex-col md:flex-row">
<Toaster position="top-center" closeButton={true} /> <Toaster position="top-center" closeButton={true} />
<div className="scrollbar-container order-last mb-10 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none"> <div className="scrollbar-container order-last mb-2 mt-2 flex h-full w-full flex-col overflow-y-auto pb-2 md:order-none">
<Heading as="h4" className="mb-2"> <Heading as="h4" className="mb-2">
{t("general.title")} {t("general.title")}
</Heading> </Heading>