diff options
Diffstat (limited to 'apps/web/src/components')
| -rw-r--r-- | apps/web/src/components/auth-form.tsx | 6 | ||||
| -rw-r--r-- | apps/web/src/components/editor/properties-panel.tsx | 1 | ||||
| -rw-r--r-- | apps/web/src/components/editor/timeline.tsx | 44 | ||||
| -rw-r--r-- | apps/web/src/components/header.tsx | 31 | ||||
| -rw-r--r-- | apps/web/src/components/landing/hero.tsx | 21 |
5 files changed, 87 insertions, 16 deletions
diff --git a/apps/web/src/components/auth-form.tsx b/apps/web/src/components/auth-form.tsx index 182137ef..3dd56036 100644 --- a/apps/web/src/components/auth-form.tsx +++ b/apps/web/src/components/auth-form.tsx @@ -54,7 +54,7 @@ const authConfig = { description: "Sign in to your account to continue",
buttonText: "Sign in",
linkText: "Don't have an account?",
- linkHref: "/auth/signup",
+ linkHref: "/signup",
linkLabel: "Sign up",
successRedirect: "/editor",
},
@@ -63,9 +63,9 @@ const authConfig = { description: "Get started with your free account today",
buttonText: "Create account",
linkText: "Already have an account?",
- linkHref: "/auth/login",
+ linkHref: "/login",
linkLabel: "Sign in",
- successRedirect: "/auth/login",
+ successRedirect: "/login",
},
} as const;
diff --git a/apps/web/src/components/editor/properties-panel.tsx b/apps/web/src/components/editor/properties-panel.tsx index 2b211c21..c784dab8 100644 --- a/apps/web/src/components/editor/properties-panel.tsx +++ b/apps/web/src/components/editor/properties-panel.tsx @@ -38,7 +38,6 @@ export function PropertiesPanel() { ? mediaItems.find((item) => item.id === firstVideoClip.mediaId) : null; - // Get the first image clip for preview (simplified) const firstImageClip = tracks .flatMap((track) => track.clips) .find((clip) => { diff --git a/apps/web/src/components/editor/timeline.tsx b/apps/web/src/components/editor/timeline.tsx index 064d0dd2..41e842bb 100644 --- a/apps/web/src/components/editor/timeline.tsx +++ b/apps/web/src/components/editor/timeline.tsx @@ -317,11 +317,21 @@ export function Timeline() { }
};
- // Deselect all clips when clicking empty timeline area
+ const handleSeekToPosition = (e: React.MouseEvent) => {
+ const rect = e.currentTarget.getBoundingClientRect();
+ const clickX = e.clientX - rect.left;
+ const clickedTime = clickX / (50 * zoomLevel);
+ const clampedTime = Math.max(0, Math.min(duration, clickedTime));
+
+ seek(clampedTime);
+ };
+
const handleTimelineAreaClick = (e: React.MouseEvent) => {
- // Only clear selection if the click target is the timeline background (not a child/clip)
if (e.target === e.currentTarget) {
clearSelectedClips();
+
+ // Calculate the clicked time position and seek to it
+ handleSeekToPosition(e);
}
};
@@ -604,10 +614,14 @@ export function Timeline() { <div className="flex-1 relative overflow-hidden">
<ScrollArea className="w-full">
<div
- className="relative h-12 bg-muted/30"
+ className="relative h-12 bg-muted/30 cursor-pointer"
style={{
width: `${Math.max(1000, duration * 50 * zoomLevel)}px`,
}}
+ onClick={(e) => {
+ // Calculate the clicked time position and seek to it
+ handleSeekToPosition(e);
+ }}
>
{/* Time markers */}
{(() => {
@@ -674,8 +688,26 @@ export function Timeline() { {/* Playhead in ruler */}
<div
- className="absolute top-0 bottom-0 w-0.5 bg-red-500 pointer-events-none z-10"
+ className="absolute top-0 bottom-0 w-0.5 bg-red-500 cursor-ew-resize z-1000" // Remove pointer-events-none to allow dragging
style={{ left: `${currentTime * 50 * zoomLevel}px` }}
+ onMouseDown={(e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ const handleMouseMove = (e: MouseEvent) => {
+ const timeline = timelineRef.current; // Get timeline element ref to track the position
+ if (!timeline) return; // If no timeline element, exit
+ const rect = timeline.getBoundingClientRect(); // Get the bounding rect of the timeline element
+ const mouseX = Math.max(0, e.clientX - rect.left); // Calculate the mouse position relative to the timeline element
+ const newTime = mouseX / (50 * zoomLevel); // Calculate the time based on the mouse position
+ seek(newTime); // Set the current time
+ };
+ const handleMouseUp = () => {
+ window.removeEventListener("mousemove", handleMouseMove); // Remove the mousemove event listener
+ window.removeEventListener("mouseup", handleMouseUp); // Remove the mouseup event listener
+ };
+ window.addEventListener("mousemove", handleMouseMove); // Add the mousemove event listener
+ window.addEventListener("mouseup", handleMouseUp); // Add the mouseup event listener
+ }}
>
<div className="absolute top-1 left-1/2 transform -translate-x-1/2 w-3 h-3 bg-red-500 rounded-full border-2 border-white shadow-sm" />
</div>
@@ -785,7 +817,7 @@ export function Timeline() { {/* Playhead for tracks area */}
<div
- className="absolute top-0 w-0.5 bg-red-500 pointer-events-none z-20"
+ className="absolute top-0 w-0.5 bg-red-500 cursor-ew-resize z-20"
style={{
left: `${currentTime * 50 * zoomLevel}px`,
height: `${tracks.length * 60}px`,
@@ -1633,4 +1665,4 @@ function TimelineTrackContent({ </div>
</div>
);
-}
\ No newline at end of file +}
diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx index 109d022e..9f842b24 100644 --- a/apps/web/src/components/header.tsx +++ b/apps/web/src/components/header.tsx @@ -6,9 +6,27 @@ import { Button } from "./ui/button"; import { ArrowRight } from "lucide-react";
import { HeaderBase } from "./header-base";
import { useSession } from "@/lib/auth-client";
+import { getStars } from "@/lib/fetchGhStars";
+import { Star } from "lucide-react";
+import { useEffect, useState } from "react";
export function Header() {
const { data: session } = useSession();
+ const [star, setStar] = useState<string>("");
+
+ useEffect(() => {
+ const fetchStars = async () => {
+ try {
+ const data = await getStars();
+ setStar(data);
+ } catch (err) {
+ console.error("Failed to fetch GitHub stars", err);
+ }
+ };
+
+ fetchStars();
+ }, []);
+
const leftContent = (
<Link href="/" className="flex items-center gap-3">
<Image src="/logo.png" alt="OpenCut Logo" width={24} height={24} />
@@ -19,11 +37,18 @@ export function Header() { const rightContent = (
<nav className="flex items-center">
<Link href="https://github.com/OpenCut-app/OpenCut" target="_blank">
- <Button variant="ghost" className="text-sm">
- GitHub
+ <Button
+ variant="ghost"
+ className="flex items-center text-sm text-muted-foreground hover:text-foreground"
+ >
+ <span className="hidden sm:inline">GitHub</span>
+ <span className="text-foreground flex items-center">
+ {star}+
+ <Star className="w-4 h-4 ml-1" />
+ </span>
</Button>
</Link>
- <Link href={session ? "/editor" : "/auth/login"}>
+ <Link href={session ? "/editor" : "/login"}>
<Button size="sm" className="text-sm ml-4">
Start editing
<ArrowRight className="h-4 w-4" />
diff --git a/apps/web/src/components/landing/hero.tsx b/apps/web/src/components/landing/hero.tsx index 714d432b..7b2586c3 100644 --- a/apps/web/src/components/landing/hero.tsx +++ b/apps/web/src/components/landing/hero.tsx @@ -5,18 +5,33 @@ import { Button } from "../ui/button"; import { Input } from "../ui/input";
import { ArrowRight } from "lucide-react";
import Link from "next/link";
-import { useState } from "react";
+import { useEffect, useState } from "react";
import { useToast } from "@/hooks/use-toast";
+import { getStars } from "@/lib/fetchGhStars";
interface HeroProps {
signupCount: number;
}
export function Hero({ signupCount }: HeroProps) {
+ const [star, setStar] = useState<string>();
const [email, setEmail] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const { toast } = useToast();
+ useEffect(() => {
+ const fetchStars = async () => {
+ try {
+ const data = await getStars();
+ setStar(data);
+ } catch (err) {
+ console.error("Failed to fetch GitHub stars", err);
+ }
+ };
+
+ fetchStars();
+ }, []);
+
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
@@ -67,7 +82,7 @@ export function Hero({ signupCount }: HeroProps) { };
return (
- <div className="relative min-h-screen flex flex-col items-center justify-center text-center px-4">
+ <div className="relative min-h-[calc(100vh-4rem)] flex flex-col items-center justify-center text-center px-4">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
@@ -152,7 +167,7 @@ export function Hero({ signupCount }: HeroProps) { href="https://github.com/OpenCut-app/OpenCut"
className="text-foreground underline"
>
- GitHub
+ GitHub {star}+
</Link>
</motion.div>
</div>
|
