From 444312460dc427000b577a987f5ef57e23e8d1b9 Mon Sep 17 00:00:00 2001 From: Abhishek Dhatrak Date: Sat, 23 May 2026 21:41:07 +0530 Subject: [PATCH 1/4] add-intro-splash-screen --- src/app/layout.tsx | 2 ++ src/components/SplashScreen.tsx | 47 +++++++++++++++++++++++++++++++++ src/components/ThemeToggle.tsx | 17 ++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 src/components/SplashScreen.tsx diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 593f68c8..301bd00f 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -6,6 +6,7 @@ import { ThemeProvider } from "@/components/ThemeProvider"; import { ThemeToggle } from "@/components/ThemeToggle"; import ScrollToTop from "@/components/ScrollToTop"; import BrandLogo from "@/components/BrandLogo"; +import SplashScreen from "@/components/SplashScreen"; export const metadata: Metadata = { title: "Reframe — Resize, trim, and export videos in your browser", @@ -75,6 +76,7 @@ export default function RootLayout({ Skip to main content +
{ + // Give the app a moment to load and display the splash screen + const fadeOutTimer = setTimeout(() => { + setIsFadingOut(true); + }, 1800); + + // Completely unmount after fade transition + const removeTimer = setTimeout(() => { + setIsVisible(false); + }, 2300); + + return () => { + clearTimeout(fadeOutTimer); + clearTimeout(removeTimer); + }; + }, []); + + // Avoid hydration mismatch by only rendering after mount + if (!isVisible) return null; + + return ( +
+
+ +

+ Reframe +

+
+
+ ); +} diff --git a/src/components/ThemeToggle.tsx b/src/components/ThemeToggle.tsx index b94b2b13..4e838941 100644 --- a/src/components/ThemeToggle.tsx +++ b/src/components/ThemeToggle.tsx @@ -1,11 +1,28 @@ "use client"; +import { useState, useEffect } from "react"; import { useTheme } from "./ThemeProvider"; export function ThemeToggle() { const { theme, toggleTheme } = useTheme(); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + const isDark = theme === "dark"; + if (!mounted) { + return ( + + ); + })} + + + {/* Brightness */}
diff --git a/src/components/VideoPreview.tsx b/src/components/VideoPreview.tsx index 4e6f7e9d..5dc4c891 100644 --- a/src/components/VideoPreview.tsx +++ b/src/components/VideoPreview.tsx @@ -197,6 +197,11 @@ export default function VideoPreview({ file, recipe, videoRef }: Props) { ref={videoRef} controls className={cn("w-full h-full object-contain transition-opacity duration-300", isLoading ? "opacity-0" : "opacity-100")} + style={{ + filter: recipe + ? `brightness(${1 + recipe.brightness}) contrast(${recipe.contrast}) saturate(${recipe.saturation})` + : undefined, + }} onLoadedData={() => setIsLoading(false)} playsInline muted={!recipe?.keepAudio} diff --git a/test.mp4 b/test.mp4 new file mode 100644 index 00000000..1becba2b --- /dev/null +++ b/test.mp4 @@ -0,0 +1 @@ +404: Not Found \ No newline at end of file From 51681351f017facaee8c0e8320a66d8c0478b8f2 Mon Sep 17 00:00:00 2001 From: Abhishek Dhatrak Date: Sat, 23 May 2026 23:24:05 +0530 Subject: [PATCH 3/4] visual audio waveform --- src/components/TrimControl.tsx | 101 +++++++++++++++++---------------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/src/components/TrimControl.tsx b/src/components/TrimControl.tsx index 577dc1fa..633a7dbf 100644 --- a/src/components/TrimControl.tsx +++ b/src/components/TrimControl.tsx @@ -178,61 +178,64 @@ export default function TrimControl({ recipe, onChange, duration, file }: Props) return (
{duration > 0 && ( -
{ - if (dragging.current) return; - const s = xToSeconds(e.clientX); - onChange({ trimStart: s }); - }} - onKeyDown={(e) => { - if (e.key === "ArrowLeft") onChange({ trimStart: Math.max(0, recipe.trimStart - 0.1) }); - if (e.key === "ArrowRight") onChange({ trimStart: Math.min((recipe.trimEnd ?? duration) - 0.1, recipe.trimStart + 0.1) }); - }} - > -
+
+
{ + if (dragging.current) return; + const s = xToSeconds(e.clientX); + onChange({ trimStart: s }); }} - /> -
{ dragging.current = "start"; }} - onTouchStart={() => { dragging.current = "start"; }} onKeyDown={(e) => { if (e.key === "ArrowLeft") onChange({ trimStart: Math.max(0, recipe.trimStart - 0.1) }); if (e.key === "ArrowRight") onChange({ trimStart: Math.min((recipe.trimEnd ?? duration) - 0.1, recipe.trimStart + 0.1) }); }} - /> -
{ dragging.current = "end"; }} - onTouchStart={() => { dragging.current = "end"; }} - onKeyDown={(e) => { - if (e.key === "ArrowLeft") onChange({ trimEnd: Math.max(recipe.trimStart + 0.1, (recipe.trimEnd ?? duration) - 0.1) }); - if (e.key === "ArrowRight") onChange({ trimEnd: Math.min(duration, (recipe.trimEnd ?? duration) + 0.1) }); - }} - /> + > +
+
+
{ dragging.current = "start"; }} + onTouchStart={() => { dragging.current = "start"; }} + onKeyDown={(e) => { + if (e.key === "ArrowLeft") onChange({ trimStart: Math.max(0, recipe.trimStart - 0.1) }); + if (e.key === "ArrowRight") onChange({ trimStart: Math.min((recipe.trimEnd ?? duration) - 0.1, recipe.trimStart + 0.1) }); + }} + /> +
{ dragging.current = "end"; }} + onTouchStart={() => { dragging.current = "end"; }} + onKeyDown={(e) => { + if (e.key === "ArrowLeft") onChange({ trimEnd: Math.max(recipe.trimStart + 0.1, (recipe.trimEnd ?? duration) - 0.1) }); + if (e.key === "ArrowRight") onChange({ trimEnd: Math.min(duration, (recipe.trimEnd ?? duration) + 0.1) }); + }} + /> +
)}
From 5ea2f42ab6a38fdfb4286d3c0aaa9a17e7187d49 Mon Sep 17 00:00:00 2001 From: Abhishek Dhatrak Date: Sun, 24 May 2026 15:47:21 +0530 Subject: [PATCH 4/4] chore: remove test.mp4 binary --- test.mp4 | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test.mp4 diff --git a/test.mp4 b/test.mp4 deleted file mode 100644 index 1becba2b..00000000 --- a/test.mp4 +++ /dev/null @@ -1 +0,0 @@ -404: Not Found \ No newline at end of file