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:
Josh Hawkins 2024-05-07 09:00:25 -05:00 committed by GitHub
parent a0da5018bf
commit 08e5c791c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 94 additions and 26 deletions

View File

@ -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>
);

View File

@ -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 ? (

View File

@ -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)

View File

@ -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"}`}

View File

@ -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>

View File

@ -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" />

View File

@ -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}

View File

@ -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)} />
);
}

View File

@ -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} />

View File

@ -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>

View File

@ -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]) => (

View File

@ -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]" />

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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">

View File

@ -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}

View File

@ -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">