mirror of
				https://github.com/blakeblackshear/frigate.git
				synced 2025-10-27 10:52:11 +01:00 
			
		
		
		
	UI tweaks (#11036)
* spacing, mobile navbar, and minor color updates * tab scrolling behavior
This commit is contained in:
		
							parent
							
								
									d6dfa596de
								
							
						
					
					
						commit
						3b0f9988df
					
				| @ -154,7 +154,7 @@ export default function MotionTuner({ | ||||
|   return ( | ||||
|     <div className="flex flex-col md:flex-row size-full"> | ||||
|       <Toaster position="top-center" /> | ||||
|       <div className="flex flex-col w-full overflow-y-auto mt-2 md:mt-0 md:w-3/12 order-last md:order-none md:mr-2 rounded-lg border-secondary-foreground border-[1px] p-2 bg-background_alt"> | ||||
|       <div className="flex flex-col h-full w-full overflow-y-auto mt-2 md:mt-0 mb-10 md:mb-0 md:w-3/12 order-last md:order-none md:mr-2 rounded-lg border-secondary-foreground border-[1px] p-2 bg-background_alt"> | ||||
|         <Heading as="h3" className="my-2"> | ||||
|           Motion Detection Tuner | ||||
|         </Heading> | ||||
|  | ||||
| @ -352,7 +352,7 @@ function Logs() { | ||||
|           {Object.values(logTypes).map((item) => ( | ||||
|             <ToggleGroupItem | ||||
|               key={item} | ||||
|               className={`flex items-center justify-between gap-2 ${logService == item ? "" : "text-gray-500"}`} | ||||
|               className={`flex items-center justify-between gap-2 ${logService == item ? "" : "text-muted-foreground"}`} | ||||
|               value={item} | ||||
|               aria-label={`Select ${item}`} | ||||
|             > | ||||
|  | ||||
| @ -20,7 +20,7 @@ import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer"; | ||||
| import MotionTuner from "@/components/settings/MotionTuner"; | ||||
| import MasksAndZones from "@/components/settings/MasksAndZones"; | ||||
| import { Button } from "@/components/ui/button"; | ||||
| import { useCallback, useEffect, useMemo, useState } from "react"; | ||||
| import { useCallback, useEffect, useMemo, useRef, useState } from "react"; | ||||
| import useOptimisticState from "@/hooks/use-optimistic-state"; | ||||
| import { isMobile } from "react-device-detect"; | ||||
| import { FaVideo } from "react-icons/fa"; | ||||
| @ -31,6 +31,8 @@ import FilterSwitch from "@/components/filter/FilterSwitch"; | ||||
| import { ZoneMaskFilterButton } from "@/components/filter/ZoneMaskFilter"; | ||||
| import { PolygonType } from "@/types/canvas"; | ||||
| import ObjectSettings from "@/components/settings/ObjectSettings"; | ||||
| import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; | ||||
| import scrollIntoView from "scroll-into-view-if-needed"; | ||||
| 
 | ||||
| export default function Settings() { | ||||
|   const settingsViews = [ | ||||
| @ -43,6 +45,7 @@ export default function Settings() { | ||||
|   type SettingsType = (typeof settingsViews)[number]; | ||||
|   const [page, setPage] = useState<SettingsType>("general"); | ||||
|   const [pageToggle, setPageToggle] = useOptimisticState(page, setPage, 100); | ||||
|   const tabsRef = useRef<HTMLDivElement | null>(null); | ||||
| 
 | ||||
|   const { data: config } = useSWR<FrigateConfig>("config"); | ||||
| 
 | ||||
| @ -83,33 +86,51 @@ export default function Settings() { | ||||
|     // eslint-disable-next-line react-hooks/exhaustive-deps
 | ||||
|   }, []); | ||||
| 
 | ||||
|   useEffect(() => { | ||||
|     if (tabsRef.current) { | ||||
|       const element = tabsRef.current.querySelector( | ||||
|         `[data-nav-item="${pageToggle}"]`, | ||||
|       ); | ||||
|       if (element instanceof HTMLElement) { | ||||
|         scrollIntoView(element, { | ||||
|           behavior: "smooth", | ||||
|           inline: "start", | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   }, [tabsRef, pageToggle]); | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="size-full p-2 flex flex-col"> | ||||
|       <div className="w-full h-11 relative flex justify-between items-center"> | ||||
|         <div className="flex flex-row overflow-x-auto"> | ||||
|           <ToggleGroup | ||||
|             className="*:px-3 *:py-4 *:rounded-md flex-shrink-0" | ||||
|             type="single" | ||||
|             size="sm" | ||||
|             value={pageToggle} | ||||
|             onValueChange={(value: SettingsType) => { | ||||
|               if (value) { | ||||
|                 setPageToggle(value); | ||||
|               } | ||||
|             }} | ||||
|           > | ||||
|             {Object.values(settingsViews).map((item) => ( | ||||
|               <ToggleGroupItem | ||||
|                 key={item} | ||||
|                 className={`flex items-center justify-between gap-2 ${pageToggle == item ? "" : "*:text-muted-foreground"}`} | ||||
|                 value={item} | ||||
|                 aria-label={`Select ${item}`} | ||||
|               > | ||||
|                 <div className="capitalize">{item}</div> | ||||
|               </ToggleGroupItem> | ||||
|             ))} | ||||
|           </ToggleGroup> | ||||
|         </div> | ||||
|         <ScrollArea className="w-full whitespace-nowrap"> | ||||
|           <div ref={tabsRef} className="flex flex-row"> | ||||
|             <ToggleGroup | ||||
|               className="*:px-3 *:py-4 *:rounded-md" | ||||
|               type="single" | ||||
|               size="sm" | ||||
|               value={pageToggle} | ||||
|               onValueChange={(value: SettingsType) => { | ||||
|                 if (value) { | ||||
|                   setPageToggle(value); | ||||
|                 } | ||||
|               }} | ||||
|             > | ||||
|               {Object.values(settingsViews).map((item) => ( | ||||
|                 <ToggleGroupItem | ||||
|                   key={item} | ||||
|                   className={`flex items-center justify-between gap-2 scroll-mx-10 ${page == "general" ? "last:mr-20" : ""} ${pageToggle == item ? "" : "*:text-muted-foreground"}`} | ||||
|                   value={item} | ||||
|                   data-nav-item={item} | ||||
|                   aria-label={`Select ${item}`} | ||||
|                 > | ||||
|                   <div className="capitalize">{item}</div> | ||||
|                 </ToggleGroupItem> | ||||
|               ))} | ||||
|             </ToggleGroup> | ||||
|             <ScrollBar orientation="horizontal" className="h-0" /> | ||||
|           </div> | ||||
|         </ScrollArea> | ||||
|         {(page == "objects" || | ||||
|           page == "masks / zones" || | ||||
|           page == "motion tuner") && ( | ||||
|  | ||||
| @ -52,7 +52,7 @@ function System() { | ||||
|           {Object.values(metrics).map((item) => ( | ||||
|             <ToggleGroupItem | ||||
|               key={item} | ||||
|               className={`flex items-center justify-between gap-2 ${pageToggle == item ? "" : "*:text-gray-500"}`} | ||||
|               className={`flex items-center justify-between gap-2 ${pageToggle == item ? "" : "*:text-muted-foreground"}`} | ||||
|               value={item} | ||||
|               aria-label={`Select ${item}`} | ||||
|             > | ||||
|  | ||||
| @ -228,7 +228,7 @@ export default function EventView({ | ||||
|           } // don't allow the severity to be unselected
 | ||||
|         > | ||||
|           <ToggleGroupItem | ||||
|             className={`${severityToggle == "alert" ? "" : "text-gray-500"}`} | ||||
|             className={`${severityToggle == "alert" ? "" : "text-muted-foreground"}`} | ||||
|             value="alert" | ||||
|             aria-label="Select alerts" | ||||
|           > | ||||
| @ -238,7 +238,7 @@ export default function EventView({ | ||||
|             </div> | ||||
|           </ToggleGroupItem> | ||||
|           <ToggleGroupItem | ||||
|             className={`${severityToggle == "detection" ? "" : "text-gray-500"}`} | ||||
|             className={`${severityToggle == "detection" ? "" : "text-muted-foreground"}`} | ||||
|             value="detection" | ||||
|             aria-label="Select detections" | ||||
|           > | ||||
| @ -250,7 +250,9 @@ export default function EventView({ | ||||
|           </ToggleGroupItem> | ||||
|           <ToggleGroupItem | ||||
|             className={`px-3 py-4 rounded-2xl ${ | ||||
|               severityToggle == "significant_motion" ? "" : "text-gray-500" | ||||
|               severityToggle == "significant_motion" | ||||
|                 ? "" | ||||
|                 : "text-muted-foreground" | ||||
|             }`}
 | ||||
|             value="significant_motion" | ||||
|             aria-label="Select motion" | ||||
|  | ||||
| @ -321,14 +321,14 @@ export function RecordingView({ | ||||
|               } // don't allow the severity to be unselected
 | ||||
|             > | ||||
|               <ToggleGroupItem | ||||
|                 className={`${timelineType == "timeline" ? "" : "text-gray-500"}`} | ||||
|                 className={`${timelineType == "timeline" ? "" : "text-muted-foreground"}`} | ||||
|                 value="timeline" | ||||
|                 aria-label="Select timeline" | ||||
|               > | ||||
|                 <div className="">Timeline</div> | ||||
|               </ToggleGroupItem> | ||||
|               <ToggleGroupItem | ||||
|                 className={`${timelineType == "events" ? "" : "text-gray-500"}`} | ||||
|                 className={`${timelineType == "events" ? "" : "text-muted-foreground"}`} | ||||
|                 value="events" | ||||
|                 aria-label="Select events" | ||||
|               > | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user