summaryrefslogtreecommitdiff
path: root/apps/web/src/components/ui
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/components/ui')
-rw-r--r--apps/web/src/components/ui/dialog.tsx12
-rw-r--r--apps/web/src/components/ui/drag-overlay.tsx25
-rw-r--r--apps/web/src/components/ui/draggable-item.tsx55
-rw-r--r--apps/web/src/components/ui/sponsor-button.tsx40
-rw-r--r--apps/web/src/components/ui/tooltip.tsx2
5 files changed, 102 insertions, 32 deletions
diff --git a/apps/web/src/components/ui/dialog.tsx b/apps/web/src/components/ui/dialog.tsx
index 0a487d0a..ebfd8907 100644
--- a/apps/web/src/components/ui/dialog.tsx
+++ b/apps/web/src/components/ui/dialog.tsx
@@ -22,7 +22,7 @@ const DialogOverlay = React.forwardRef<
<DialogPrimitive.Overlay
ref={ref}
className={cn(
- "fixed inset-0 z-50 bg-black/80 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-[100] bg-black/20 backdrop-blur-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className
)}
{...props}
@@ -39,9 +39,17 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
- "fixed left-[50%] top-[50%] z-50 grid w-[calc(100%-2rem)] max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
+ "fixed left-[50%] top-[50%] z-[150] grid w-[calc(100%-2rem)] max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-popover shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className
)}
+ onCloseAutoFocus={(e) => {
+ e.stopPropagation();
+ e.preventDefault();
+ }}
+ onOpenAutoFocus={(e) => {
+ e.stopPropagation();
+ e.preventDefault();
+ }}
{...props}
>
<ScrollArea className="max-h-[85vh]">
diff --git a/apps/web/src/components/ui/drag-overlay.tsx b/apps/web/src/components/ui/drag-overlay.tsx
deleted file mode 100644
index ba6fe08f..00000000
--- a/apps/web/src/components/ui/drag-overlay.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Upload } from "lucide-react";
-
-interface DragOverlayProps {
- isVisible: boolean;
- title?: string;
- description?: string;
-}
-
-export function DragOverlay({
- isVisible,
- title = "Drop files here",
- description = "Images, videos, and audio files",
-}: DragOverlayProps) {
- if (!isVisible) return null;
-
- return (
- <div className="absolute inset-0 bg-accent/20 backdrop-blur-lg border-2 border-dashed border-accent flex items-center justify-center z-10 pointer-events-none">
- <div className="text-center">
- <Upload className="h-8 w-8 text-accent mx-auto mb-2" />
- <p className="text-sm font-medium text-accent">{title}</p>
- <p className="text-xs text-muted-foreground">{description}</p>
- </div>
- </div>
- );
-}
diff --git a/apps/web/src/components/ui/draggable-item.tsx b/apps/web/src/components/ui/draggable-item.tsx
index 16518dde..b15e8df8 100644
--- a/apps/web/src/components/ui/draggable-item.tsx
+++ b/apps/web/src/components/ui/draggable-item.tsx
@@ -2,16 +2,23 @@
import { AspectRatio } from "@/components/ui/aspect-ratio";
import { Button } from "@/components/ui/button";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipTrigger,
+} from "@/components/ui/tooltip";
import { ReactNode, useState, useRef, useEffect } from "react";
import { createPortal } from "react-dom";
import { Plus } from "lucide-react";
import { cn } from "@/lib/utils";
+import { usePlaybackStore } from "@/stores/playback-store";
export interface DraggableMediaItemProps {
name: string;
preview: ReactNode;
dragData: Record<string, any>;
onDragStart?: (e: React.DragEvent) => void;
+ onAddToTimeline?: (currentTime: number) => void;
aspectRatio?: number;
className?: string;
showPlusOnDrag?: boolean;
@@ -24,6 +31,7 @@ export function DraggableMediaItem({
preview,
dragData,
onDragStart,
+ onAddToTimeline,
aspectRatio = 16 / 9,
className = "",
showPlusOnDrag = true,
@@ -33,6 +41,11 @@ export function DraggableMediaItem({
const [isDragging, setIsDragging] = useState(false);
const [dragPosition, setDragPosition] = useState({ x: 0, y: 0 });
const dragRef = useRef<HTMLDivElement>(null);
+ const currentTime = usePlaybackStore((state) => state.currentTime);
+
+ const handleAddToTimeline = () => {
+ onAddToTimeline?.(currentTime);
+ };
const emptyImg = new window.Image();
emptyImg.src =
@@ -92,7 +105,10 @@ export function DraggableMediaItem({
>
{preview}
{!isDragging && (
- <PlusButton className="opacity-0 group-hover:opacity-100" />
+ <PlusButton
+ className="opacity-0 group-hover:opacity-100"
+ onClick={handleAddToTimeline}
+ />
)}
</AspectRatio>
{showLabel && (
@@ -128,7 +144,12 @@ export function DraggableMediaItem({
<div className="w-full h-full [&_img]:w-full [&_img]:h-full [&_img]:object-cover [&_img]:rounded-none">
{preview}
</div>
- {showPlusOnDrag && <PlusButton />}
+ {showPlusOnDrag && (
+ <PlusButton
+ onClick={handleAddToTimeline}
+ tooltipText="Add to timeline or drag to position"
+ />
+ )}
</AspectRatio>
</div>
</div>,
@@ -138,13 +159,39 @@ export function DraggableMediaItem({
);
}
-function PlusButton({ className }: { className?: string }) {
- return (
+function PlusButton({
+ className,
+ onClick,
+ tooltipText,
+}: {
+ className?: string;
+ onClick?: () => void;
+ tooltipText?: string;
+}) {
+ const button = (
<Button
size="icon"
className={cn("absolute bottom-2 right-2 size-4", className)}
+ onClick={(e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ onClick?.();
+ }}
>
<Plus className="!size-3" />
</Button>
);
+
+ if (tooltipText) {
+ return (
+ <Tooltip>
+ <TooltipTrigger asChild>{button}</TooltipTrigger>
+ <TooltipContent>
+ <p>{tooltipText}</p>
+ </TooltipContent>
+ </Tooltip>
+ );
+ }
+
+ return button;
}
diff --git a/apps/web/src/components/ui/sponsor-button.tsx b/apps/web/src/components/ui/sponsor-button.tsx
new file mode 100644
index 00000000..79c708a2
--- /dev/null
+++ b/apps/web/src/components/ui/sponsor-button.tsx
@@ -0,0 +1,40 @@
+import { motion } from "motion/react";
+import { ComponentType } from "react";
+
+interface SponsorButtonProps {
+ href: string;
+ logo: ComponentType<{ className?: string }>;
+ companyName: string;
+ className?: string;
+}
+
+export function SponsorButton({
+ href,
+ logo: Logo,
+ companyName,
+ className = "",
+}: SponsorButtonProps) {
+
+ return (
+ <motion.a
+ href={href}
+ target="_blank"
+ rel="noopener noreferrer"
+ className={`inline-flex items-center gap-2 px-3 py-2 rounded-full border border-white/10 bg-white/5 backdrop-blur-sm hover:bg-white/10 hover:border-white/20 transition-all duration-200 group shadow-lg ${className}`}
+ >
+ <span className="text-xs font-medium text-zinc-400 group-hover:text-zinc-300 transition-colors">
+ Sponsored by
+ </span>
+
+ <div className="flex items-center gap-1.5">
+ <div className="text-zinc-100 group-hover:text-white transition-colors">
+ <Logo className="w-4 h-4" />
+ </div>
+
+ <span className="text-xs font-medium text-zinc-100 group-hover:text-white transition-colors">
+ {companyName}
+ </span>
+ </div>
+ </motion.a>
+ );
+}
diff --git a/apps/web/src/components/ui/tooltip.tsx b/apps/web/src/components/ui/tooltip.tsx
index a2fb0a01..4971e262 100644
--- a/apps/web/src/components/ui/tooltip.tsx
+++ b/apps/web/src/components/ui/tooltip.tsx
@@ -20,7 +20,7 @@ const TooltipContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
- "z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs 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 overflow-hidden rounded-md bg-foreground px-3 py-1.5 text-xs text-background 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",
className
)}
{...props}