From 02c9f90a99cfa8c1a8fdc35735be23cdeadfc9a8 Mon Sep 17 00:00:00 2001 From: Mahdy Arief Date: Sun, 29 Mar 2026 09:46:49 +0700 Subject: [PATCH 1/8] feat(editor): implement blur annotation with CSS-driven preview and robust canvas export pipeline --- .../video-editor/AnnotationOverlay.tsx | 17 ++- .../video-editor/AnnotationSettingsPanel.tsx | 49 +++++- src/components/video-editor/SettingsPanel.tsx | 15 +- src/components/video-editor/VideoEditor.tsx | 92 ++++++----- src/components/video-editor/VideoPlayback.tsx | 39 ++--- src/components/video-editor/types.ts | 3 +- src/lib/exporter/annotationRenderer.ts | 143 +++++++++++++----- 7 files changed, 246 insertions(+), 112 deletions(-) diff --git a/src/components/video-editor/AnnotationOverlay.tsx b/src/components/video-editor/AnnotationOverlay.tsx index 3260a542..31b2e043 100644 --- a/src/components/video-editor/AnnotationOverlay.tsx +++ b/src/components/video-editor/AnnotationOverlay.tsx @@ -50,8 +50,8 @@ export function AnnotationOverlay({
@@ -111,6 +111,17 @@ export function AnnotationOverlay({
); + case 'blur': + return ( +
+ ); + default: return null; } @@ -127,7 +138,7 @@ export function AnnotationOverlay({ const xPercent = (d.x / containerWidth) * 100; const yPercent = (d.y / containerHeight) * 100; onPositionChange(annotation.id, { x: xPercent, y: yPercent }); - + // Reset dragging flag after a short delay to prevent click event setTimeout(() => { isDraggingRef.current = false; diff --git a/src/components/video-editor/AnnotationSettingsPanel.tsx b/src/components/video-editor/AnnotationSettingsPanel.tsx index 2cddf970..2dbb8e67 100644 --- a/src/components/video-editor/AnnotationSettingsPanel.tsx +++ b/src/components/video-editor/AnnotationSettingsPanel.tsx @@ -21,6 +21,7 @@ interface AnnotationSettingsPanelProps { onTypeChange: (type: AnnotationType) => void; onStyleChange: (style: Partial) => void; onFigureDataChange?: (figureData: FigureData) => void; + onBlurIntensityChange?: (intensity: number) => void; onDelete: () => void; } @@ -43,6 +44,7 @@ export function AnnotationSettingsPanel({ onTypeChange, onStyleChange, onFigureDataChange, + onBlurIntensityChange, onDelete, }: AnnotationSettingsPanelProps) { const t = useScopedT('editor'); @@ -128,21 +130,29 @@ export function AnnotationSettingsPanel({ {/* Type Selector */} onTypeChange(value as AnnotationType)} className="mb-6"> - - - + + + {t('annotations.text')} - - + + {t('annotations.image')} - - + + {t('annotations.arrow')} + + + + + + + {t('annotations.blur', 'Blur')} + {/* Text Content */} @@ -499,6 +509,31 @@ export function AnnotationSettingsPanel({
+ +
+
+ + + {annotation.blurIntensity ?? 12}% + +
+ { + onBlurIntensityChange?.(value); + }} + min={1} + max={100} + step={1} + className="w-full" + /> +

+ {t('annotations.blurDescription', 'Obscure sensitive information by blurring the underlying video content.')} +

+
+
- - - - - ); + return ( +
+
+ setActiveTab(value as "screens" | "windows")} + > + + + {t("sourceSelector.screens")} ({screenSources.length}) + + + {t("sourceSelector.windows")} ({windowSources.length}) + + +
+ +
+ {screenSources.length === 0 && ( +
+ No screens available +
+ )} + {screenSources.map((source) => ( + handleSourceSelect(source)} + > +
+
+ {source.name} + {selectedSource?.id === source.id && ( +
+
+ +
+
+ )} +
+
{source.name}
+
+
+ ))} +
+
+ +

+ {t("sourceSelector.windowsNote")} +

+
+ {windowSources.length === 0 && ( +
+ No windows available +
+ )} + {windowSources.map((source) => ( + handleSourceSelect(source)} + > +
+
+ {source.thumbnail ? ( + {source.name} + ) : ( +
+ {source.appIcon ? ( + App icon + ) : ( +
+ )} +
+ {t("sourceSelector.windowPlaceholder")} +
+
+ )} + {selectedSource?.id === source.id && ( +
+
+ +
+
+ )} +
+
+ {source.appIcon && ( + App icon + )} +
{source.name}
+
+
+ + ))} +
+ +
+ +
+
+
+ + +
+
+
+ ); } - diff --git a/src/components/launch/UpdateToastWindow.tsx b/src/components/launch/UpdateToastWindow.tsx index 100a2339..eb7342d2 100644 --- a/src/components/launch/UpdateToastWindow.tsx +++ b/src/components/launch/UpdateToastWindow.tsx @@ -190,9 +190,7 @@ export function UpdateToastWindow() {

Checking for updates

-

- Waiting for updater state from the main process. -

+

Waiting for updater state from the main process.

@@ -287,7 +285,9 @@ export function UpdateToastWindow() { >
{payload.phase === "available" ? : null} - {payload.phase === "downloading" ? : null} + {payload.phase === "downloading" ? ( + + ) : null} {payload.phase === "ready" ? : null} {payload.phase === "error" ? : null}
@@ -295,7 +295,19 @@ export function UpdateToastWindow() {

{getToastTitle(payload)}

{payload.isPreview ? ( - + Dev ) : null} @@ -304,22 +316,39 @@ export function UpdateToastWindow() { {payload.phase === "downloading" ? (
-
+
-

{normalizedProgress}% downloaded

+

+ {normalizedProgress}% downloaded +

) : null}
{primaryActionLabel ? ( - ) : null} @@ -386,4 +415,4 @@ export function UpdateToastWindow() {
); -} \ No newline at end of file +} diff --git a/src/components/ui/accordion.tsx b/src/components/ui/accordion.tsx index 8c106859..85336fde 100644 --- a/src/components/ui/accordion.tsx +++ b/src/components/ui/accordion.tsx @@ -1,56 +1,55 @@ -import * as React from "react" -import * as AccordionPrimitive from "@radix-ui/react-accordion" -import { ChevronDown } from "lucide-react" +import * as AccordionPrimitive from "@radix-ui/react-accordion"; +import { ChevronDown } from "lucide-react"; +import * as React from "react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; -const Accordion = AccordionPrimitive.Root +const Accordion = AccordionPrimitive.Root; const AccordionItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -AccordionItem.displayName = "AccordionItem" + +)); +AccordionItem.displayName = "AccordionItem"; const AccordionTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - svg]:rotate-180", - className - )} - {...props} - > - {children} - - - -)) -AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName + + svg]:rotate-180", + className, + )} + {...props} + > + {children} + + + +)); +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName; const AccordionContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - -
{children}
-
-)) -AccordionContent.displayName = AccordionPrimitive.Content.displayName - -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } + +
{children}
+
+)); +AccordionContent.displayName = AccordionPrimitive.Content.displayName; +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/src/components/ui/audio-level-meter.tsx b/src/components/ui/audio-level-meter.tsx index d5b209d2..55e4bd1e 100644 --- a/src/components/ui/audio-level-meter.tsx +++ b/src/components/ui/audio-level-meter.tsx @@ -1,37 +1,37 @@ interface AudioLevelMeterProps { - level: number; - className?: string; + level: number; + className?: string; } const bars = [ - { threshold: 10, height: '30%' }, - { threshold: 25, height: '45%' }, - { threshold: 45, height: '60%' }, - { threshold: 65, height: '75%' }, - { threshold: 85, height: '90%' }, -] + { threshold: 10, height: "30%" }, + { threshold: 25, height: "45%" }, + { threshold: 45, height: "60%" }, + { threshold: 65, height: "75%" }, + { threshold: 85, height: "90%" }, +]; function getBarColor(level: number, threshold: number) { - if (!level || level < threshold) return 'bg-slate-700' - if (threshold > 80) return 'bg-red-500' - if (threshold > 60) return 'bg-yellow-500' - if (threshold > 40) return 'bg-blue-500' - return 'bg-blue-400' + if (!level || level < threshold) return "bg-slate-700"; + if (threshold > 80) return "bg-red-500"; + if (threshold > 60) return "bg-yellow-500"; + if (threshold > 40) return "bg-blue-500"; + return "bg-blue-400"; } -export function AudioLevelMeter({ level, className = '' }: AudioLevelMeterProps) { - return ( -
- {bars.map((bar, index) => ( -
= bar.threshold ? bar.height : '15%', - opacity: level >= bar.threshold ? 1 : 0.4, - }} - /> - ))} -
- ) +export function AudioLevelMeter({ level, className = "" }: AudioLevelMeterProps) { + return ( +
+ {bars.map((bar, index) => ( +
= bar.threshold ? bar.height : "15%", + opacity: level >= bar.threshold ? 1 : 0.4, + }} + /> + ))} +
+ ); } diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 266f0e09..c4606018 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -1,58 +1,50 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; +import * as React from "react"; -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-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", - { - variants: { - variant: { - default: - "bg-primary text-primary-foreground shadow hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", - outline: - "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-9 px-4 py-2", - sm: "h-8 rounded-md px-3 text-xs", - lg: "h-10 rounded-md px-8", - icon: "h-9 w-9", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - } -) + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground shadow hover:bg-primary/90", + destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", + outline: + "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", + secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; } const Button = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" - return ( - - ) - } -) -Button.displayName = "Button" - -export { Button, buttonVariants } + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + }, +); +Button.displayName = "Button"; +export { Button, buttonVariants }; diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx index d7ca9454..2935ed46 100644 --- a/src/components/ui/card.tsx +++ b/src/components/ui/card.tsx @@ -1,77 +1,55 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -const Card = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -Card.displayName = "Card" - -const CardHeader = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardHeader.displayName = "CardHeader" - -const CardTitle = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardTitle.displayName = "CardTitle" - -const CardDescription = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardDescription.displayName = "CardDescription" - -const CardContent = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardContent.displayName = "CardContent" - -const CardFooter = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardFooter.displayName = "CardFooter" - -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } - +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Card = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ), +); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ), +); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ), +); +CardTitle.displayName = "CardTitle"; + +const CardDescription = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ), +); +CardDescription.displayName = "CardDescription"; + +const CardContent = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ), +); +CardContent.displayName = "CardContent"; + +const CardFooter = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ), +); +CardFooter.displayName = "CardFooter"; + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }; diff --git a/src/components/ui/content-clamp.tsx b/src/components/ui/content-clamp.tsx index 4435e9ec..f03e4df1 100644 --- a/src/components/ui/content-clamp.tsx +++ b/src/components/ui/content-clamp.tsx @@ -1,87 +1,81 @@ -"use client" +"use client"; -import * as React from "react" +import * as React from "react"; -import { cn } from "@/lib/utils" -import { Popover, PopoverArrow, PopoverContent, PopoverTrigger } from "./popover" +import { cn } from "@/lib/utils"; +import { Popover, PopoverArrow, PopoverContent, PopoverTrigger } from "./popover"; interface ContentClampProps extends React.HTMLAttributes { - children: React.ReactNode - truncateLength?: number + children: React.ReactNode; + truncateLength?: number; } -function ContentClamp({ - children, - className, - truncateLength = 50, - ...props -}: ContentClampProps) { - const text = typeof children === "string" ? children : String(children ?? "") - const isTruncated = text.length > truncateLength +function ContentClamp({ children, className, truncateLength = 50, ...props }: ContentClampProps) { + const text = typeof children === "string" ? children : String(children ?? ""); + const isTruncated = text.length > truncateLength; - const [open, setOpen] = React.useState(false) - const timeoutRef = React.useRef(null) + const [open, setOpen] = React.useState(false); + const timeoutRef = React.useRef(null); - const handleMouseEnter = () => { - if (timeoutRef.current) { - clearTimeout(timeoutRef.current) - timeoutRef.current = null - } - setOpen(true) - } + const handleMouseEnter = () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + timeoutRef.current = null; + } + setOpen(true); + }; - const handleMouseLeave = () => { - timeoutRef.current = setTimeout(() => { - setOpen(false) - }, 100) - } + const handleMouseLeave = () => { + timeoutRef.current = setTimeout(() => { + setOpen(false); + }, 100); + }; - React.useEffect(() => { - return () => { - if (timeoutRef.current) { - clearTimeout(timeoutRef.current) - } - } - }, []) + React.useEffect(() => { + return () => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + }; + }, []); - if (!isTruncated) { - return ( -
- {children} -
- ) - } + if (!isTruncated) { + return ( +
+ {children} +
+ ); + } - const truncatedText = text.slice(0, truncateLength) + "..." + const truncatedText = text.slice(0, truncateLength) + "..."; - return ( - - - e.preventDefault()} - {...props} - > - {truncatedText} - - - e.preventDefault()} - onClick={(e) => e.stopPropagation()} - > - - {children} - - - ) + return ( + + + e.preventDefault()} + {...props} + > + {truncatedText} + + + e.preventDefault()} + onClick={(e) => e.stopPropagation()} + > + + {children} + + + ); } -export { ContentClamp } - +export { ContentClamp }; diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx index 697b3b88..0c3efbb2 100644 --- a/src/components/ui/dialog.tsx +++ b/src/components/ui/dialog.tsx @@ -1,121 +1,102 @@ -import * as React from "react" -import * as DialogPrimitive from "@radix-ui/react-dialog" -import { X } from "lucide-react" +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { X } from "lucide-react"; +import * as React from "react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; -const Dialog = DialogPrimitive.Root +const Dialog = DialogPrimitive.Root; -const DialogTrigger = DialogPrimitive.Trigger +const DialogTrigger = DialogPrimitive.Trigger; -const DialogPortal = DialogPrimitive.Portal +const DialogPortal = DialogPrimitive.Portal; -const DialogClose = DialogPrimitive.Close +const DialogClose = DialogPrimitive.Close; const DialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; const DialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - - - {children} - - - Close - - - -)) -DialogContent.displayName = DialogPrimitive.Content.displayName + + + + {children} + + + Close + + + +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; -const DialogHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -DialogHeader.displayName = "DialogHeader" +const DialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = "DialogHeader"; -const DialogFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -DialogFooter.displayName = "DialogFooter" +const DialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( +
+); +DialogFooter.displayName = "DialogFooter"; const DialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -DialogTitle.displayName = DialogPrimitive.Title.displayName + +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; const DialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -DialogDescription.displayName = DialogPrimitive.Description.displayName + +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; export { - Dialog, - DialogPortal, - DialogOverlay, - DialogTrigger, - DialogClose, - DialogContent, - DialogHeader, - DialogFooter, - DialogTitle, - DialogDescription, -} - + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx index d8ce2db3..c15187de 100644 --- a/src/components/ui/dropdown-menu.tsx +++ b/src/components/ui/dropdown-menu.tsx @@ -1,200 +1,186 @@ -import * as React from "react" -import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" -import { Check, ChevronRight, Circle } from "lucide-react" +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { Check, ChevronRight, Circle } from "lucide-react"; +import * as React from "react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; -const DropdownMenu = DropdownMenuPrimitive.Root +const DropdownMenu = DropdownMenuPrimitive.Root; -const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; -const DropdownMenuGroup = DropdownMenuPrimitive.Group +const DropdownMenuGroup = DropdownMenuPrimitive.Group; -const DropdownMenuPortal = DropdownMenuPrimitive.Portal +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; -const DropdownMenuSub = DropdownMenuPrimitive.Sub +const DropdownMenuSub = DropdownMenuPrimitive.Sub; -const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; const DropdownMenuSubTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } >(({ className, inset, children, ...props }, ref) => ( - - {children} - - -)) -DropdownMenuSubTrigger.displayName = - DropdownMenuPrimitive.SubTrigger.displayName + + {children} + + +)); +DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName; const DropdownMenuSubContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -DropdownMenuSubContent.displayName = - DropdownMenuPrimitive.SubContent.displayName + +)); +DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName; const DropdownMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, sideOffset = 4, ...props }, ref) => ( - - - -)) -DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; const DropdownMenuItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } >(({ className, inset, ...props }, ref) => ( - svg]:size-4 [&>svg]:shrink-0", - inset && "pl-8", - className - )} - {...props} - /> -)) -DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName + svg]:size-4 [&>svg]:shrink-0", + inset && "pl-8", + className, + )} + {...props} + /> +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; const DropdownMenuCheckboxItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, checked, ...props }, ref) => ( - - - - - - - {children} - -)) -DropdownMenuCheckboxItem.displayName = - DropdownMenuPrimitive.CheckboxItem.displayName + + + + + + + {children} + +)); +DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName; const DropdownMenuRadioItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( - - - - - - - {children} - -)) -DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName + + + + + + + {children} + +)); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; const DropdownMenuLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } >(({ className, inset, ...props }, ref) => ( - -)) -DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; const DropdownMenuSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName - -const DropdownMenuShortcut = ({ - className, - ...props -}: React.HTMLAttributes) => { - return ( - - ) -} -DropdownMenuShortcut.displayName = "DropdownMenuShortcut" + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { + return ( + + ); +}; +DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; export { - DropdownMenu, - DropdownMenuTrigger, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuCheckboxItem, - DropdownMenuRadioItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuGroup, - DropdownMenuPortal, - DropdownMenuSub, - DropdownMenuSubContent, - DropdownMenuSubTrigger, - DropdownMenuRadioGroup, -} - + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +}; diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index 7ba03f87..b5e4484c 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -1,25 +1,23 @@ -import * as React from "react" -import { cn } from "@/lib/utils" +import * as React from "react"; +import { cn } from "@/lib/utils"; -export interface InputProps - extends React.InputHTMLAttributes {} +export interface InputProps extends React.InputHTMLAttributes {} const Input = React.forwardRef( - ({ className, type, ...props }, ref) => { - return ( - - ) - } -) -Input.displayName = "Input" + ({ className, type, ...props }, ref) => { + return ( + + ); + }, +); +Input.displayName = "Input"; -export { Input } - +export { Input }; diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx index 67784787..fe3a2883 100644 --- a/src/components/ui/label.tsx +++ b/src/components/ui/label.tsx @@ -1,24 +1,20 @@ -import * as React from "react" -import { cn } from "@/lib/utils" +import * as React from "react"; +import { cn } from "@/lib/utils"; -export interface LabelProps - extends React.LabelHTMLAttributes {} +export interface LabelProps extends React.LabelHTMLAttributes {} -const Label = React.forwardRef( - ({ className, ...props }, ref) => { - return ( -