mirror of
https://github.com/blakeblackshear/frigate.git
synced 2024-11-21 19:07:46 +01:00
Use cn() for class names throughout (#11278)
* add scrollbar on ptz presets dropdown
* use cn function for class names throughout
* Revert "add scrollbar on ptz presets dropdown"
This reverts commit 2cee93dc3e
.
This commit is contained in:
parent
a0da5018bf
commit
08e5c791c8
@ -1,9 +1,11 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type LogoProps = {
|
||||
className?: string;
|
||||
};
|
||||
export default function Logo({ className }: LogoProps) {
|
||||
return (
|
||||
<svg viewBox="0 0 512 512" className={`fill-current ${className}`}>
|
||||
<svg viewBox="0 0 512 512" className={cn("fill-current", className)}>
|
||||
<path d="M130 446.5C131.6 459.3 145 468 137 470C129 472 94 406.5 86 378.5C78 350.5 73.5 319 75.5 301C77.4999 283 181 255 181 247.5C181 240 147.5 247 146 241C144.5 235 171.3 238.6 178.5 229C189.75 214 204 216.5 213 208.5C222 200.5 233 170 235 157C237 144 215 129 209 119C203 109 222 102 268 83C314 64 460 22 462 27C464 32 414 53 379 66C344 79 287 104 287 111C287 118 290 123.5 288 139.5C286 155.5 285.76 162.971 282 173.5C279.5 180.5 277 197 282 212C286 224 299 233 305 235C310 235.333 323.8 235.8 339 235C358 234 385 236 385 241C385 246 344 243 344 250C344 257 386 249 385 256C384 263 350 260 332 260C317.6 260 296.333 259.333 287 256L285 263C281.667 263 274.7 265 267.5 265C258.5 265 258 268 241.5 268C225 268 230 267 215 266C200 265 144 308 134 322C124 336 130 370 130 385.5C130 399.428 128 430.5 130 446.5Z" />
|
||||
</svg>
|
||||
);
|
||||
|
@ -3,6 +3,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import useSWR from "swr";
|
||||
import ActivityIndicator from "../indicators/activity-indicator";
|
||||
import { useResizeObserver } from "@/hooks/resize-observer";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type CameraImageProps = {
|
||||
className?: string;
|
||||
@ -95,7 +96,7 @@ export default function CameraImage({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative w-full h-full flex justify-center ${className}`}
|
||||
className={cn("relative w-full h-full flex justify-center", className)}
|
||||
ref={containerRef}
|
||||
>
|
||||
{enabled ? (
|
||||
|
@ -18,6 +18,7 @@ import useKeyboardListener from "@/hooks/use-keyboard-listener";
|
||||
import { DeleteClipType, Export } from "@/types/export";
|
||||
import { MdEditSquare } from "react-icons/md";
|
||||
import { baseUrl } from "@/api/baseUrl";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type ExportProps = {
|
||||
className: string;
|
||||
@ -104,7 +105,10 @@ export default function ExportCard({
|
||||
</Dialog>
|
||||
|
||||
<div
|
||||
className={`relative aspect-video bg-black rounded-lg md:rounded-2xl flex justify-center items-center ${className}`}
|
||||
className={cn(
|
||||
"relative aspect-video bg-black rounded-lg md:rounded-2xl flex justify-center items-center",
|
||||
className,
|
||||
)}
|
||||
onMouseEnter={
|
||||
isDesktop && !exportedRecording.in_progress
|
||||
? () => setHovered(true)
|
||||
|
@ -5,6 +5,7 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { isDesktop } from "react-device-detect";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const variants = {
|
||||
primary: {
|
||||
@ -38,9 +39,11 @@ export default function CameraFeatureToggle({
|
||||
const content = (
|
||||
<div
|
||||
onClick={onClick}
|
||||
className={`${className} flex flex-col justify-center items-center ${
|
||||
variants[variant][isActive ? "active" : "inactive"]
|
||||
}`}
|
||||
className={cn(
|
||||
className,
|
||||
"flex flex-col justify-center items-center",
|
||||
variants[variant][isActive ? "active" : "inactive"],
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
className={`size-5 md:m-[6px] ${isActive ? "text-white" : "text-secondary-foreground"}`}
|
||||
|
@ -60,6 +60,7 @@ import { toast } from "sonner";
|
||||
import ActivityIndicator from "../indicators/activity-indicator";
|
||||
import { ScrollArea, ScrollBar } from "../ui/scroll-area";
|
||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type CameraGroupSelectorProps = {
|
||||
className?: string;
|
||||
@ -120,7 +121,11 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
|
||||
/>
|
||||
<Scroller className={`${isMobile ? "whitespace-nowrap" : ""}`}>
|
||||
<div
|
||||
className={`flex items-center justify-start gap-2 ${className ?? ""} ${isDesktop ? "flex-col" : "whitespace-nowrap"}`}
|
||||
className={cn(
|
||||
"flex items-center justify-start gap-2",
|
||||
className,
|
||||
isDesktop ? "flex-col" : "whitespace-nowrap",
|
||||
)}
|
||||
>
|
||||
<Tooltip open={tooltip == "default"}>
|
||||
<TooltipTrigger asChild>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { LuPlus } from "react-icons/lu";
|
||||
import Logo from "../Logo";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type FrigatePlusIconProps = {
|
||||
className?: string;
|
||||
@ -11,7 +12,7 @@ export default function FrigatePlusIcon({
|
||||
}: FrigatePlusIconProps) {
|
||||
return (
|
||||
<div
|
||||
className={`relative flex items-center ${className ?? ""}`}
|
||||
className={cn("relative flex items-center", className)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<Logo className="size-full" />
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { LogSeverity } from "@/types/log";
|
||||
import { ReactNode, useMemo, useRef } from "react";
|
||||
import { CSSTransition } from "react-transition-group";
|
||||
@ -32,7 +33,10 @@ export default function Chip({
|
||||
>
|
||||
<div
|
||||
ref={nodeRef}
|
||||
className={`flex px-2 py-1.5 rounded-2xl items-center z-10 ${className}`}
|
||||
className={cn(
|
||||
"flex px-2 py-1.5 rounded-2xl items-center z-10",
|
||||
className,
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
{children}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { isSafari } from "react-device-detect";
|
||||
import { Skeleton } from "../ui/skeleton";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export default function ImageLoadingIndicator({
|
||||
className,
|
||||
@ -13,8 +14,8 @@ export default function ImageLoadingIndicator({
|
||||
}
|
||||
|
||||
return isSafari ? (
|
||||
<div className={`bg-gray-300 pointer-events-none ${className ?? ""}`} />
|
||||
<div className={cn("bg-gray-300 pointer-events-none", className)} />
|
||||
) : (
|
||||
<Skeleton className={`pointer-events-none ${className ?? ""}`} />
|
||||
<Skeleton className={cn("pointer-events-none", className)} />
|
||||
);
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { LuLoader2 } from "react-icons/lu";
|
||||
|
||||
export default function ActivityIndicator({ className = "w-full", size = 30 }) {
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center justify-center ${className}`}
|
||||
className={cn("flex items-center justify-center", className)}
|
||||
aria-label="Loading…"
|
||||
>
|
||||
<LuLoader2 className="animate-spin" size={size} />
|
||||
|
@ -3,6 +3,7 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||
import { isDesktop } from "react-device-detect";
|
||||
import { VscAccount } from "react-icons/vsc";
|
||||
@ -15,7 +16,13 @@ export default function AccountSettings({ className }: AccountSettingsProps) {
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<div
|
||||
className={`flex flex-col justify-center items-center ${isDesktop ? "rounded-lg text-secondary-foreground bg-secondary hover:bg-muted cursor-pointer" : "text-secondary-foreground"} ${className ?? ""}`}
|
||||
className={cn(
|
||||
"flex flex-col justify-center items-center",
|
||||
isDesktop
|
||||
? "rounded-lg text-secondary-foreground bg-secondary hover:bg-muted cursor-pointer"
|
||||
: "text-secondary-foreground",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<VscAccount className="size-5 md:m-[6px]" />
|
||||
</div>
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
StatusMessage,
|
||||
} from "@/context/statusbar-provider";
|
||||
import { Link } from "react-router-dom";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function Bottombar() {
|
||||
const navItems = useNavigation("secondary");
|
||||
@ -75,7 +76,10 @@ function StatusAlertNav({ className }: StatusAlertNavProps) {
|
||||
<IoIosWarning className="size-5 text-danger" />
|
||||
</DrawerTrigger>
|
||||
<DrawerContent
|
||||
className={`max-h-[75dvh] px-2 mx-1 rounded-t-2xl overflow-hidden ${className ?? ""}`}
|
||||
className={cn(
|
||||
"max-h-[75dvh] px-2 mx-1 rounded-t-2xl overflow-hidden",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="w-full h-auto py-4 overflow-y-auto overflow-x-hidden flex flex-col items-center gap-2">
|
||||
{Object.entries(messages).map(([key, messageArray]) => (
|
||||
|
@ -8,6 +8,7 @@ import { isDesktop } from "react-device-detect";
|
||||
import { TooltipPortal } from "@radix-ui/react-tooltip";
|
||||
import { NavData } from "@/types/navigation";
|
||||
import { IconType } from "react-icons";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const variants = {
|
||||
primary: {
|
||||
@ -42,9 +43,11 @@ export default function NavItem({
|
||||
to={item.url}
|
||||
onClick={onClick}
|
||||
className={({ isActive }) =>
|
||||
`flex flex-col justify-center items-center rounded-lg ${className ?? ""} ${
|
||||
variants[item.variant ?? "primary"][isActive ? "active" : "inactive"]
|
||||
}`
|
||||
cn(
|
||||
"flex flex-col justify-center items-center rounded-lg",
|
||||
className,
|
||||
variants[item.variant ?? "primary"][isActive ? "active" : "inactive"],
|
||||
)
|
||||
}
|
||||
>
|
||||
<Icon className="size-5 md:m-[6px]" />
|
||||
|
@ -4,6 +4,7 @@ import ActivityIndicator from "../indicators/activity-indicator";
|
||||
import JSMpegPlayer from "./JSMpegPlayer";
|
||||
import MSEPlayer from "./MsePlayer";
|
||||
import { LivePlayerMode } from "@/types/live";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type LivePlayerProps = {
|
||||
className?: string;
|
||||
@ -57,7 +58,10 @@ export default function BirdseyeLivePlayer({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative flex justify-center w-full cursor-pointer ${className ?? ""}`}
|
||||
className={cn(
|
||||
"relative flex justify-center w-full cursor-pointer",
|
||||
className,
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="absolute top-0 inset-x-0 rounded-lg md:rounded-2xl z-10 w-full h-[30%] bg-gradient-to-b from-black/20 to-transparent pointer-events-none"></div>
|
||||
|
@ -13,6 +13,7 @@ import useCameraLiveMode from "@/hooks/use-camera-live-mode";
|
||||
import { getIconForLabel } from "@/utils/iconUtil";
|
||||
import Chip from "../indicators/Chip";
|
||||
import { capitalizeFirstLetter } from "@/utils/stringUtil";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type LivePlayerProps = {
|
||||
cameraRef?: (ref: HTMLDivElement | null) => void;
|
||||
@ -150,11 +151,16 @@ export default function LivePlayer({
|
||||
<div
|
||||
ref={cameraRef}
|
||||
data-camera={cameraConfig.name}
|
||||
className={`relative flex justify-center ${liveMode == "jsmpeg" ? "size-full" : "w-full"} outline cursor-pointer ${
|
||||
className={cn(
|
||||
"relative flex justify-center",
|
||||
liveMode === "jsmpeg" ? "size-full" : "w-full",
|
||||
"outline cursor-pointer",
|
||||
activeTracking
|
||||
? "outline-severity_alert outline-3 rounded-lg md:rounded-2xl shadow-severity_alert"
|
||||
: "outline-0 outline-background"
|
||||
} transition-all duration-500 ${className}`}
|
||||
: "outline-0 outline-background",
|
||||
"transition-all duration-500",
|
||||
className,
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="absolute top-0 inset-x-0 rounded-lg md:rounded-2xl z-10 w-full h-[30%] bg-gradient-to-b from-black/20 to-transparent pointer-events-none"></div>
|
||||
|
@ -15,6 +15,7 @@ import { baseUrl } from "@/api/baseUrl";
|
||||
import { isAndroid, isChrome, isMobile } from "react-device-detect";
|
||||
import { TimeRange } from "@/types/timeline";
|
||||
import { Skeleton } from "../ui/skeleton";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type PreviewPlayerProps = {
|
||||
className?: string;
|
||||
@ -238,7 +239,11 @@ function PreviewVideoPlayer({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative rounded-lg md:rounded-2xl w-full flex justify-center bg-black overflow-hidden ${onClick ? "cursor-pointer" : ""} ${className ?? ""}`}
|
||||
className={cn(
|
||||
"relative rounded-lg md:rounded-2xl w-full flex justify-center bg-black overflow-hidden",
|
||||
onClick && "cursor-pointer",
|
||||
className,
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<img
|
||||
@ -476,7 +481,11 @@ function PreviewFramesPlayer({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative w-full flex justify-center ${className ?? ""} ${onClick ? "cursor-pointer" : ""}`}
|
||||
className={cn(
|
||||
"relative w-full flex justify-center",
|
||||
className,
|
||||
onClick && "cursor-pointer",
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<img
|
||||
|
@ -29,6 +29,7 @@ import {
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
} from "../ui/alert-dialog";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type VideoControls = {
|
||||
volume?: boolean;
|
||||
@ -161,7 +162,10 @@ export default function VideoControls({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`px-4 py-2 flex justify-between items-center gap-8 text-primary z-50 bg-background/60 rounded-lg ${className ?? ""}`}
|
||||
className={cn(
|
||||
"px-4 py-2 flex justify-between items-center gap-8 text-primary z-50 bg-background/60 rounded-lg",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{video && features.volume && (
|
||||
<div className="flex justify-normal items-center gap-2 cursor-pointer">
|
||||
|
@ -11,6 +11,7 @@ import { TimeRange } from "@/types/timeline";
|
||||
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||
import { VideoResolutionType } from "@/types/live";
|
||||
import axios from "axios";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/**
|
||||
* Dynamically switches between video playback and scrubbing preview player.
|
||||
@ -202,7 +203,10 @@ export default function DynamicVideoPlayer({
|
||||
onUploadFrame={onUploadFrameToPlus}
|
||||
/>
|
||||
<PreviewPlayer
|
||||
className={`${isScrubbing || isLoading ? "visible" : "hidden"} ${className}`}
|
||||
className={cn(
|
||||
isScrubbing || isLoading ? "visible" : "hidden",
|
||||
className,
|
||||
)}
|
||||
camera={camera}
|
||||
timeRange={timeRange}
|
||||
cameraPreviews={cameraPreviews}
|
||||
|
@ -12,6 +12,7 @@ import { Toaster } from "@/components/ui/sonner";
|
||||
import { toast } from "sonner";
|
||||
import { isDesktop } from "react-device-detect";
|
||||
import ActivityIndicator from "@/components/indicators/activity-indicator";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const logTypes = ["frigate", "go2rtc", "nginx"] as const;
|
||||
type LogType = (typeof logTypes)[number];
|
||||
@ -472,7 +473,11 @@ function LogLineData({
|
||||
return (
|
||||
<div
|
||||
ref={startRef}
|
||||
className={`w-full py-2 grid grid-cols-5 sm:grid-cols-8 md:grid-cols-12 gap-2 border-secondary border-t cursor-pointer hover:bg-muted ${className} *:text-sm`}
|
||||
className={cn(
|
||||
"w-full py-2 grid grid-cols-5 sm:grid-cols-8 md:grid-cols-12 gap-2 border-secondary border-t cursor-pointer hover:bg-muted",
|
||||
className,
|
||||
"*:text-sm",
|
||||
)}
|
||||
onClick={onSelect}
|
||||
>
|
||||
<div className="h-full p-1 flex items-center gap-2">
|
||||
|
Loading…
Reference in New Issue
Block a user