feat(UI): Adding linter and prettier for UI (#3156)

This commit is contained in:
Francisco Arceo 2025-08-14 15:58:43 -06:00 committed by GitHub
parent 61582f327c
commit e69acbafbf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
73 changed files with 1452 additions and 1226 deletions

View file

@ -1,6 +1,6 @@
"use client"
"use client";
import { useEffect, useRef } from "react"
import { useEffect, useRef } from "react";
// Configuration constants for the audio analyzer
const AUDIO_CONFIG = {
@ -14,12 +14,12 @@ const AUDIO_CONFIG = {
MAX_INTENSITY: 255, // Maximum gray value (brighter)
INTENSITY_RANGE: 155, // MAX_INTENSITY - MIN_INTENSITY
},
} as const
} as const;
interface AudioVisualizerProps {
stream: MediaStream | null
isRecording: boolean
onClick: () => void
stream: MediaStream | null;
isRecording: boolean;
onClick: () => void;
}
export function AudioVisualizer({
@ -28,91 +28,91 @@ export function AudioVisualizer({
onClick,
}: AudioVisualizerProps) {
// Refs for managing audio context and animation
const canvasRef = useRef<HTMLCanvasElement>(null)
const audioContextRef = useRef<AudioContext | null>(null)
const analyserRef = useRef<AnalyserNode | null>(null)
const animationFrameRef = useRef<number>()
const containerRef = useRef<HTMLDivElement>(null)
const canvasRef = useRef<HTMLCanvasElement>(null);
const audioContextRef = useRef<AudioContext | null>(null);
const analyserRef = useRef<AnalyserNode | null>(null);
const animationFrameRef = useRef<number>();
const containerRef = useRef<HTMLDivElement>(null);
// Cleanup function to stop visualization and close audio context
const cleanup = () => {
if (animationFrameRef.current) {
cancelAnimationFrame(animationFrameRef.current)
cancelAnimationFrame(animationFrameRef.current);
}
if (audioContextRef.current) {
audioContextRef.current.close()
audioContextRef.current.close();
}
}
};
// Cleanup on unmount
useEffect(() => {
return cleanup
}, [])
return cleanup;
}, []);
// Start or stop visualization based on recording state
useEffect(() => {
if (stream && isRecording) {
startVisualization()
startVisualization();
} else {
cleanup()
cleanup();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [stream, isRecording])
}, [stream, isRecording]);
// Handle window resize
useEffect(() => {
const handleResize = () => {
if (canvasRef.current && containerRef.current) {
const container = containerRef.current
const canvas = canvasRef.current
const dpr = window.devicePixelRatio || 1
const container = containerRef.current;
const canvas = canvasRef.current;
const dpr = window.devicePixelRatio || 1;
// Set canvas size based on container and device pixel ratio
const rect = container.getBoundingClientRect()
const rect = container.getBoundingClientRect();
// Account for the 2px total margin (1px on each side)
canvas.width = (rect.width - 2) * dpr
canvas.height = (rect.height - 2) * dpr
canvas.width = (rect.width - 2) * dpr;
canvas.height = (rect.height - 2) * dpr;
// Scale canvas CSS size to match container minus margins
canvas.style.width = `${rect.width - 2}px`
canvas.style.height = `${rect.height - 2}px`
canvas.style.width = `${rect.width - 2}px`;
canvas.style.height = `${rect.height - 2}px`;
}
}
};
window.addEventListener("resize", handleResize)
window.addEventListener("resize", handleResize);
// Initial setup
handleResize()
handleResize();
return () => window.removeEventListener("resize", handleResize)
}, [])
return () => window.removeEventListener("resize", handleResize);
}, []);
// Initialize audio context and start visualization
const startVisualization = async () => {
try {
const audioContext = new AudioContext()
audioContextRef.current = audioContext
const audioContext = new AudioContext();
audioContextRef.current = audioContext;
const analyser = audioContext.createAnalyser()
analyser.fftSize = AUDIO_CONFIG.FFT_SIZE
analyser.smoothingTimeConstant = AUDIO_CONFIG.SMOOTHING
analyserRef.current = analyser
const analyser = audioContext.createAnalyser();
analyser.fftSize = AUDIO_CONFIG.FFT_SIZE;
analyser.smoothingTimeConstant = AUDIO_CONFIG.SMOOTHING;
analyserRef.current = analyser;
const source = audioContext.createMediaStreamSource(stream!)
source.connect(analyser)
const source = audioContext.createMediaStreamSource(stream!);
source.connect(analyser);
draw()
draw();
} catch (error) {
console.error("Error starting visualization:", error)
console.error("Error starting visualization:", error);
}
}
};
// Calculate the color intensity based on bar height
const getBarColor = (normalizedHeight: number) => {
const intensity =
Math.floor(normalizedHeight * AUDIO_CONFIG.COLOR.INTENSITY_RANGE) +
AUDIO_CONFIG.COLOR.MIN_INTENSITY
return `rgb(${intensity}, ${intensity}, ${intensity})`
}
AUDIO_CONFIG.COLOR.MIN_INTENSITY;
return `rgb(${intensity}, ${intensity}, ${intensity})`;
};
// Draw a single bar of the visualizer
const drawBar = (
@ -123,52 +123,52 @@ export function AudioVisualizer({
height: number,
color: string
) => {
ctx.fillStyle = color
ctx.fillStyle = color;
// Draw upper bar (above center)
ctx.fillRect(x, centerY - height, width, height)
ctx.fillRect(x, centerY - height, width, height);
// Draw lower bar (below center)
ctx.fillRect(x, centerY, width, height)
}
ctx.fillRect(x, centerY, width, height);
};
// Main drawing function
const draw = () => {
if (!isRecording) return
if (!isRecording) return;
const canvas = canvasRef.current
const ctx = canvas?.getContext("2d")
if (!canvas || !ctx || !analyserRef.current) return
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
if (!canvas || !ctx || !analyserRef.current) return;
const dpr = window.devicePixelRatio || 1
ctx.scale(dpr, dpr)
const dpr = window.devicePixelRatio || 1;
ctx.scale(dpr, dpr);
const analyser = analyserRef.current
const bufferLength = analyser.frequencyBinCount
const frequencyData = new Uint8Array(bufferLength)
const analyser = analyserRef.current;
const bufferLength = analyser.frequencyBinCount;
const frequencyData = new Uint8Array(bufferLength);
const drawFrame = () => {
animationFrameRef.current = requestAnimationFrame(drawFrame)
animationFrameRef.current = requestAnimationFrame(drawFrame);
// Get current frequency data
analyser.getByteFrequencyData(frequencyData)
analyser.getByteFrequencyData(frequencyData);
// Clear canvas - use CSS pixels for clearing
ctx.clearRect(0, 0, canvas.width / dpr, canvas.height / dpr)
ctx.clearRect(0, 0, canvas.width / dpr, canvas.height / dpr);
// Calculate dimensions in CSS pixels
const barWidth = Math.max(
AUDIO_CONFIG.MIN_BAR_WIDTH,
canvas.width / dpr / bufferLength - AUDIO_CONFIG.BAR_SPACING
)
const centerY = canvas.height / dpr / 2
let x = 0
);
const centerY = canvas.height / dpr / 2;
let x = 0;
// Draw each frequency bar
for (let i = 0; i < bufferLength; i++) {
const normalizedHeight = frequencyData[i] / 255 // Convert to 0-1 range
const normalizedHeight = frequencyData[i] / 255; // Convert to 0-1 range
const barHeight = Math.max(
AUDIO_CONFIG.MIN_BAR_HEIGHT,
normalizedHeight * centerY
)
);
drawBar(
ctx,
@ -177,14 +177,14 @@ export function AudioVisualizer({
barWidth,
barHeight,
getBarColor(normalizedHeight)
)
);
x += barWidth + AUDIO_CONFIG.BAR_SPACING
x += barWidth + AUDIO_CONFIG.BAR_SPACING;
}
}
};
drawFrame()
}
drawFrame();
};
return (
<div
@ -194,5 +194,5 @@ export function AudioVisualizer({
>
<canvas ref={canvasRef} className="h-full w-full" />
</div>
)
);
}

View file

@ -14,7 +14,7 @@ function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
data-slot="breadcrumb-list"
className={cn(
"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
className,
className
)}
{...props}
/>

View file

@ -1,8 +1,8 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
@ -33,7 +33,7 @@ const buttonVariants = cva(
size: "default",
},
}
)
);
function Button({
className,
@ -43,9 +43,9 @@ function Button({
...props
}: React.ComponentProps<"button"> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
asChild?: boolean;
}) {
const Comp = asChild ? Slot : "button"
const Comp = asChild ? Slot : "button";
return (
<Comp
@ -53,7 +53,7 @@ function Button({
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
)
);
}
export { Button, buttonVariants }
export { Button, buttonVariants };

View file

@ -8,7 +8,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card"
className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
className,
className
)}
{...props}
/>
@ -21,7 +21,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card-header"
className={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
className,
className
)}
{...props}
/>
@ -54,7 +54,7 @@ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className,
className
)}
{...props}
/>

View file

@ -1,11 +1,11 @@
"use client"
"use client";
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
function Collapsible({
...props
}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
}
function CollapsibleTrigger({
@ -16,7 +16,7 @@ function CollapsibleTrigger({
data-slot="collapsible-trigger"
{...props}
/>
)
);
}
function CollapsibleContent({
@ -27,7 +27,7 @@ function CollapsibleContent({
data-slot="collapsible-content"
{...props}
/>
)
);
}
export { Collapsible, CollapsibleTrigger, CollapsibleContent }
export { Collapsible, CollapsibleTrigger, CollapsibleContent };

View file

@ -1,21 +1,21 @@
"use client"
"use client";
import { Check, Copy } from "lucide-react"
import { Check, Copy } from "lucide-react";
import { cn } from "@/lib/utils"
import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils";
import { useCopyToClipboard } from "@/hooks/use-copy-to-clipboard";
import { Button } from "@/components/ui/button";
type CopyButtonProps = {
content: string
copyMessage?: string
}
content: string;
copyMessage?: string;
};
export function CopyButton({ content, copyMessage }: CopyButtonProps) {
const { isCopied, handleCopy } = useCopyToClipboard({
text: content,
copyMessage,
})
});
return (
<Button
@ -40,5 +40,5 @@ export function CopyButton({ content, copyMessage }: CopyButtonProps) {
)}
/>
</Button>
)
);
}

View file

@ -43,7 +43,7 @@ function DropdownMenuContent({
sideOffset={sideOffset}
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
className,
className
)}
{...props}
/>
@ -75,7 +75,7 @@ function DropdownMenuItem({
data-variant={variant}
className={cn(
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
className
)}
{...props}
/>
@ -93,7 +93,7 @@ function DropdownMenuCheckboxItem({
data-slot="dropdown-menu-checkbox-item"
className={cn(
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
className
)}
checked={checked}
{...props}
@ -129,7 +129,7 @@ function DropdownMenuRadioItem({
data-slot="dropdown-menu-radio-item"
className={cn(
"focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className,
className
)}
{...props}
>
@ -156,7 +156,7 @@ function DropdownMenuLabel({
data-inset={inset}
className={cn(
"px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
className,
className
)}
{...props}
/>
@ -185,7 +185,7 @@ function DropdownMenuShortcut({
data-slot="dropdown-menu-shortcut"
className={cn(
"text-muted-foreground ml-auto text-xs tracking-widest",
className,
className
)}
{...props}
/>
@ -212,7 +212,7 @@ function DropdownMenuSubTrigger({
data-inset={inset}
className={cn(
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8",
className,
className
)}
{...props}
>
@ -231,7 +231,7 @@ function DropdownMenuSubContent({
data-slot="dropdown-menu-sub-content"
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
className,
className
)}
{...props}
/>

View file

@ -1,18 +1,18 @@
"use client"
"use client";
import React, { useEffect } from "react"
import { motion } from "framer-motion"
import { FileIcon, X } from "lucide-react"
import React, { useEffect } from "react";
import { motion } from "framer-motion";
import { FileIcon, X } from "lucide-react";
interface FilePreviewProps {
file: File
onRemove?: () => void
file: File;
onRemove?: () => void;
}
export const FilePreview = React.forwardRef<HTMLDivElement, FilePreviewProps>(
(props, ref) => {
if (props.file.type.startsWith("image/")) {
return <ImageFilePreview {...props} ref={ref} />
return <ImageFilePreview {...props} ref={ref} />;
}
if (
@ -20,13 +20,13 @@ export const FilePreview = React.forwardRef<HTMLDivElement, FilePreviewProps>(
props.file.name.endsWith(".txt") ||
props.file.name.endsWith(".md")
) {
return <TextFilePreview {...props} ref={ref} />
return <TextFilePreview {...props} ref={ref} />;
}
return <GenericFilePreview {...props} ref={ref} />
return <GenericFilePreview {...props} ref={ref} />;
}
)
FilePreview.displayName = "FilePreview"
);
FilePreview.displayName = "FilePreview";
const ImageFilePreview = React.forwardRef<HTMLDivElement, FilePreviewProps>(
({ file, onRemove }, ref) => {
@ -62,23 +62,23 @@ const ImageFilePreview = React.forwardRef<HTMLDivElement, FilePreviewProps>(
</button>
) : null}
</motion.div>
)
);
}
)
ImageFilePreview.displayName = "ImageFilePreview"
);
ImageFilePreview.displayName = "ImageFilePreview";
const TextFilePreview = React.forwardRef<HTMLDivElement, FilePreviewProps>(
({ file, onRemove }, ref) => {
const [preview, setPreview] = React.useState<string>("")
const [preview, setPreview] = React.useState<string>("");
useEffect(() => {
const reader = new FileReader()
reader.onload = (e) => {
const text = e.target?.result as string
setPreview(text.slice(0, 50) + (text.length > 50 ? "..." : ""))
}
reader.readAsText(file)
}, [file])
const reader = new FileReader();
reader.onload = e => {
const text = e.target?.result as string;
setPreview(text.slice(0, 50) + (text.length > 50 ? "..." : ""));
};
reader.readAsText(file);
}, [file]);
return (
<motion.div
@ -111,10 +111,10 @@ const TextFilePreview = React.forwardRef<HTMLDivElement, FilePreviewProps>(
</button>
) : null}
</motion.div>
)
);
}
)
TextFilePreview.displayName = "TextFilePreview"
);
TextFilePreview.displayName = "TextFilePreview";
const GenericFilePreview = React.forwardRef<HTMLDivElement, FilePreviewProps>(
({ file, onRemove }, ref) => {
@ -147,7 +147,7 @@ const GenericFilePreview = React.forwardRef<HTMLDivElement, FilePreviewProps>(
</button>
) : null}
</motion.div>
)
);
}
)
GenericFilePreview.displayName = "GenericFilePreview"
);
GenericFilePreview.displayName = "GenericFilePreview";

View file

@ -11,7 +11,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
className,
className
)}
{...props}
/>

View file

@ -1,27 +1,27 @@
"use client"
"use client";
import * as React from "react"
import * as SelectPrimitive from "@radix-ui/react-select"
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
import * as React from "react";
import * as SelectPrimitive from "@radix-ui/react-select";
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
function Select({
...props
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
return <SelectPrimitive.Root data-slot="select" {...props} />
return <SelectPrimitive.Root data-slot="select" {...props} />;
}
function SelectGroup({
...props
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
return <SelectPrimitive.Group data-slot="select-group" {...props} />
return <SelectPrimitive.Group data-slot="select-group" {...props} />;
}
function SelectValue({
...props
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
return <SelectPrimitive.Value data-slot="select-value" {...props} />
return <SelectPrimitive.Value data-slot="select-value" {...props} />;
}
function SelectTrigger({
@ -30,7 +30,7 @@ function SelectTrigger({
children,
...props
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
size?: "sm" | "default"
size?: "sm" | "default";
}) {
return (
<SelectPrimitive.Trigger
@ -47,7 +47,7 @@ function SelectTrigger({
<ChevronDownIcon className="size-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
)
);
}
function SelectContent({
@ -82,7 +82,7 @@ function SelectContent({
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
)
);
}
function SelectLabel({
@ -95,7 +95,7 @@ function SelectLabel({
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
{...props}
/>
)
);
}
function SelectItem({
@ -119,7 +119,7 @@ function SelectItem({
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
)
);
}
function SelectSeparator({
@ -132,7 +132,7 @@ function SelectSeparator({
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
{...props}
/>
)
);
}
function SelectScrollUpButton({
@ -150,7 +150,7 @@ function SelectScrollUpButton({
>
<ChevronUpIcon className="size-4" />
</SelectPrimitive.ScrollUpButton>
)
);
}
function SelectScrollDownButton({
@ -168,7 +168,7 @@ function SelectScrollDownButton({
>
<ChevronDownIcon className="size-4" />
</SelectPrimitive.ScrollDownButton>
)
);
}
export {
@ -182,4 +182,4 @@ export {
SelectSeparator,
SelectTrigger,
SelectValue,
}
};

View file

@ -18,7 +18,7 @@ function Separator({
orientation={orientation}
className={cn(
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
className,
className
)}
{...props}
/>

View file

@ -37,7 +37,7 @@ function SheetOverlay({
data-slot="sheet-overlay"
className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
className,
className
)}
{...props}
/>
@ -67,7 +67,7 @@ function SheetContent({
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
side === "bottom" &&
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
className,
className
)}
{...props}
>

View file

@ -85,12 +85,12 @@ function SidebarProvider({
// This sets the cookie to keep the sidebar state.
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
},
[setOpenProp, open],
[setOpenProp, open]
);
// Helper to toggle the sidebar.
const toggleSidebar = React.useCallback(() => {
return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
return isMobile ? setOpenMobile(open => !open) : setOpen(open => !open);
}, [isMobile, setOpen, setOpenMobile]);
// Adds a keyboard shortcut to toggle the sidebar.
@ -123,7 +123,7 @@ function SidebarProvider({
setOpenMobile,
toggleSidebar,
}),
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
);
return (
@ -140,7 +140,7 @@ function SidebarProvider({
}
className={cn(
"group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
className,
className
)}
{...props}
>
@ -171,7 +171,7 @@ function Sidebar({
data-slot="sidebar"
className={cn(
"bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
className,
className
)}
{...props}
>
@ -223,7 +223,7 @@ function Sidebar({
"group-data-[side=right]:rotate-180",
variant === "floating" || variant === "inset"
? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
)}
/>
<div
@ -237,7 +237,7 @@ function Sidebar({
variant === "floating" || variant === "inset"
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]"
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l",
className,
className
)}
{...props}
>
@ -267,7 +267,7 @@ function SidebarTrigger({
variant="ghost"
size="icon"
className={cn("size-7", className)}
onClick={(event) => {
onClick={event => {
onClick?.(event);
toggleSidebar();
}}
@ -297,7 +297,7 @@ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
"hover:group-data-[collapsible=offcanvas]:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full",
"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
className,
className
)}
{...props}
/>
@ -311,7 +311,7 @@ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
className={cn(
"bg-background relative flex w-full flex-1 flex-col",
"md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ml-2",
className,
className
)}
{...props}
/>
@ -375,7 +375,7 @@ function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
data-sidebar="content"
className={cn(
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
className,
className
)}
{...props}
/>
@ -407,7 +407,7 @@ function SidebarGroupLabel({
className={cn(
"text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
className,
className
)}
{...props}
/>
@ -430,7 +430,7 @@ function SidebarGroupAction({
// Increases the hit area of the button on mobile.
"after:absolute after:-inset-2 md:after:hidden",
"group-data-[collapsible=icon]:hidden",
className,
className
)}
{...props}
/>
@ -492,7 +492,7 @@ const sidebarMenuButtonVariants = cva(
variant: "default",
size: "default",
},
},
}
);
function SidebarMenuButton({
@ -570,7 +570,7 @@ function SidebarMenuAction({
"group-data-[collapsible=icon]:hidden",
showOnHover &&
"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
className,
className
)}
{...props}
/>
@ -592,7 +592,7 @@ function SidebarMenuBadge({
"peer-data-[size=default]/menu-button:top-1.5",
"peer-data-[size=lg]/menu-button:top-2.5",
"group-data-[collapsible=icon]:hidden",
className,
className
)}
{...props}
/>
@ -645,7 +645,7 @@ function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
className={cn(
"border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5",
"group-data-[collapsible=icon]:hidden",
className,
className
)}
{...props}
/>
@ -691,7 +691,7 @@ function SidebarMenuSubButton({
size === "sm" && "text-xs",
size === "md" && "text-sm",
"group-data-[collapsible=icon]:hidden",
className,
className
)}
{...props}
/>

View file

@ -1,10 +1,10 @@
"use client"
"use client";
import { useTheme } from "next-themes"
import { Toaster as Sonner, ToasterProps } from "sonner"
import { useTheme } from "next-themes";
import { Toaster as Sonner, ToasterProps } from "sonner";
const Toaster = ({ ...props }: ToasterProps) => {
const { theme = "system" } = useTheme()
const { theme = "system" } = useTheme();
return (
<Sonner
@ -19,7 +19,7 @@ const Toaster = ({ ...props }: ToasterProps) => {
}
{...props}
/>
)
}
);
};
export { Toaster }
export { Toaster };

View file

@ -45,7 +45,7 @@ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
data-slot="table-footer"
className={cn(
"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
className,
className
)}
{...props}
/>
@ -58,7 +58,7 @@ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
data-slot="table-row"
className={cn(
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
className,
className
)}
{...props}
/>
@ -71,7 +71,7 @@ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
data-slot="table-head"
className={cn(
"text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className,
className
)}
{...props}
/>
@ -84,7 +84,7 @@ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
data-slot="table-cell"
className={cn(
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className,
className
)}
{...props}
/>

View file

@ -47,7 +47,7 @@ function TooltipContent({
sideOffset={sideOffset}
className={cn(
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
className,
className
)}
{...props}
>