From 6656729611b61d0338ca55810721a235a2414b99 Mon Sep 17 00:00:00 2001 From: deepika mishra Date: Tue, 9 Jun 2026 11:58:12 +0530 Subject: [PATCH 1/6] initial commit --- package-lock.json | 107 +++++------------------ src/app/page.tsx | 3 +- src/components/CustomTemplateManager.tsx | 88 +++++++++++++++++++ src/components/VideoEditor.tsx | 52 +++++++++-- src/lib/templateStorage.tsx | 54 ++++++++++++ 5 files changed, 208 insertions(+), 96 deletions(-) create mode 100644 src/components/CustomTemplateManager.tsx create mode 100644 src/lib/templateStorage.tsx diff --git a/package-lock.json b/package-lock.json index aa0316bb..fddb027f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,14 @@ "dependencies": { "@ffmpeg/ffmpeg": "^0.12.10", "@ffmpeg/util": "^0.12.2", + "clsx": "^2.1.1", "lottie-react": "^2.4.0", "lottie-web": "^5.12.2", "lucide-react": "^0.469.0", "next": "^15.1.8", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "tailwind-merge": "^3.6.0" }, "devDependencies": { "@types/node": "^22", @@ -355,9 +357,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -374,9 +373,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -393,9 +389,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -412,9 +405,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -431,9 +421,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -450,9 +437,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -469,9 +453,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -488,9 +469,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -507,9 +485,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -532,9 +507,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -557,9 +529,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -582,9 +551,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -607,9 +573,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -632,9 +595,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -657,9 +617,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -682,9 +639,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -895,9 +849,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -914,9 +865,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -933,9 +881,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -952,9 +897,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1470,9 +1412,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1487,9 +1426,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1504,9 +1440,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1521,9 +1454,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1538,9 +1468,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1555,9 +1482,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1572,9 +1496,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1589,9 +1510,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2105,6 +2023,15 @@ "version": "0.0.1", "license": "MIT" }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "dev": true, @@ -5116,6 +5043,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tailwind-merge": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz", + "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "3.4.19", "dev": true, diff --git a/src/app/page.tsx b/src/app/page.tsx index e5b632eb..cf1e5092 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -18,5 +18,4 @@ export default function Home() {
- ); -} + diff --git a/src/components/CustomTemplateManager.tsx b/src/components/CustomTemplateManager.tsx new file mode 100644 index 00000000..38b4b575 --- /dev/null +++ b/src/components/CustomTemplateManager.tsx @@ -0,0 +1,88 @@ +"use client"; + +import { useEffect, useState } from "react"; + +import { + getTemplates, + deleteTemplate, + renameTemplate, +} from "@/lib/templateStorage"; + +interface Props { + onApplyTemplate: (recipe: any) => void; +} + +export default function CustomTemplateManager({ + onApplyTemplate, +}: Props) { + const [templates, setTemplates] = useState([]); + + const refreshTemplates = () => { + setTemplates(getTemplates()); + }; + + useEffect(() => { + refreshTemplates(); + }, []); + + return ( +
+ {templates.length === 0 && ( +

+ No saved templates +

+ )} + + {templates.map((template) => ( +
+

+ {template.name} +

+ +
+ + + + + +
+
+ ))} +
+ ); +} \ No newline at end of file diff --git a/src/components/VideoEditor.tsx b/src/components/VideoEditor.tsx index 7f4ce60e..022735ad 100644 --- a/src/components/VideoEditor.tsx +++ b/src/components/VideoEditor.tsx @@ -16,6 +16,9 @@ import { Layers, Crop, Scissors, RotateCw, Volume2, SlidersHorizontal, Zap, AlertTriangle, Github } from "lucide-react"; +import CustomTemplateManager from "./CustomTemplateManager"; + +import {saveTemplate,} from "@/lib/templateStorage"; interface SectionProps { icon: React.ReactNode; @@ -50,6 +53,19 @@ export default function VideoEditor() { } = useVideoEditor(); const isProcessing = status === "loading-engine" || status === "exporting"; + const handleSaveTemplate = () => { + const name = prompt( + "Template name" + ); + + if (!name) return; + + saveTemplate({ + id: crypto.randomUUID(), + name, + recipe, + }); +}; return (
@@ -132,15 +148,33 @@ export default function VideoEditor() { "space-y-5", isProcessing && "pointer-events-none opacity-50" )}> -
-
} title="Output size"> - -
- -
} title="Framing" delay={100}> - -
-
+
+ +
} title="Templates"> + + + + updateRecipe(savedRecipe) + } + /> +
+ +
} title="Output size"> + +
+ +
} title="Framing" delay={100}> + +
+ +
- \ No newline at end of file + + + + + + + ); +} \ No newline at end of file From e8ebb55a8a5b8f44a9a05c68e1225e21563acb6e Mon Sep 17 00:00:00 2001 From: Deepika Date: Sat, 13 Jun 2026 09:43:06 +0530 Subject: [PATCH 5/6] Add Custom Template Save Feature --- src/components/CustomTemplateManager.tsx | 6 +- src/components/VideoEditor.tsx | 376 ++++++++++++----------- src/lib/templateStorage.ts | 53 ++++ src/lib/templateStorage.tsx | 15 +- 4 files changed, 254 insertions(+), 196 deletions(-) create mode 100644 src/lib/templateStorage.ts diff --git a/src/components/CustomTemplateManager.tsx b/src/components/CustomTemplateManager.tsx index 38b4b575..f05529c1 100644 --- a/src/components/CustomTemplateManager.tsx +++ b/src/components/CustomTemplateManager.tsx @@ -44,9 +44,7 @@ export default function CustomTemplateManager({
- - -
- - {/* Keyboard shortcuts */} - - - {/* Export summary */} - {file && ( -

- {exportSummary} -

- )} - - {/* Templates */} -
-
} title="Templates"> - + {recommendedPreset && ( +
+

+ We detected a {recommendedPreset.label.replace(/\s/g, "")} video → + Recommended: {(recommendedPreset.platform.split("·")[0] ?? "").trim()} ( + {recommendedPreset.label.replace(/\s/g, "")}) +

+
+ )} - updateRecipe(savedRecipe)} - /> -
-
+

+ Resize controls are available in the left panel. +

+ - + {/* Copy + Reset */} +
+ + + +
+ + {/* Keyboard shortcuts */} + + + {/* Export summary */} + {file && ( +

+ {exportSummary} +

+ )} + + {/* Templates */} +
+
} title="Templates"> + + + updateRecipe(savedRecipe)} + /> +
+
+ + diff --git a/src/lib/templateStorage.ts b/src/lib/templateStorage.ts new file mode 100644 index 00000000..2ab2088a --- /dev/null +++ b/src/lib/templateStorage.ts @@ -0,0 +1,53 @@ +export interface SavedTemplate { + id: string; + name: string; + recipe: any; +} + +const STORAGE_KEY = "reframe-custom-templates"; + +export function getTemplates(): SavedTemplate[] { + if (typeof window === "undefined") return []; + + const data = localStorage.getItem(STORAGE_KEY); + + return data ? JSON.parse(data) : []; +} + +export function saveTemplate(template: SavedTemplate) { + const templates = getTemplates(); + + templates.push(template); + + localStorage.setItem( + STORAGE_KEY, + JSON.stringify(templates) + ); +} + +export function deleteTemplate(id: string) { + const templates = getTemplates().filter( + (t) => t.id !== id + ); + + localStorage.setItem( + STORAGE_KEY, + JSON.stringify(templates) + ); +} + +export function renameTemplate( + id: string, + newName: string +) { + const templates = getTemplates().map((t) => + t.id === id + ? { ...t, name: newName } + : t + ); + + localStorage.setItem( + STORAGE_KEY, + JSON.stringify(templates) + ); +} \ No newline at end of file diff --git a/src/lib/templateStorage.tsx b/src/lib/templateStorage.tsx index f1e77288..88d8a2f9 100644 --- a/src/lib/templateStorage.tsx +++ b/src/lib/templateStorage.tsx @@ -9,9 +9,12 @@ const STORAGE_KEY = "reframe-custom-templates"; export const getTemplates = (): CustomTemplate[] => { if (typeof window === "undefined") return []; - const data = localStorage.getItem(STORAGE_KEY); - - return data ? JSON.parse(data) : []; + try { + const data = localStorage.getItem(STORAGE_KEY); + return data ? JSON.parse(data) : []; + } catch { + return []; + } }; export const saveTemplate = (template: CustomTemplate) => { @@ -23,11 +26,13 @@ export const saveTemplate = (template: CustomTemplate) => { STORAGE_KEY, JSON.stringify(templates) ); + + console.log("Saved templates:", templates); }; export const deleteTemplate = (id: string) => { const updated = getTemplates().filter( - template => template.id !== id + (template) => template.id !== id ); localStorage.setItem( @@ -41,7 +46,7 @@ export const renameTemplate = ( name: string ) => { const updated = getTemplates().map( - template => + (template) => template.id === id ? { ...template, name } : template From 4f72f818d7f8a72f0b6f9ce825deef20f3fc9529 Mon Sep 17 00:00:00 2001 From: Deepika Date: Sat, 13 Jun 2026 09:48:41 +0530 Subject: [PATCH 6/6] initial commit with branch new --- src/lib/templateStorage.ts | 53 -------------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 src/lib/templateStorage.ts diff --git a/src/lib/templateStorage.ts b/src/lib/templateStorage.ts deleted file mode 100644 index 2ab2088a..00000000 --- a/src/lib/templateStorage.ts +++ /dev/null @@ -1,53 +0,0 @@ -export interface SavedTemplate { - id: string; - name: string; - recipe: any; -} - -const STORAGE_KEY = "reframe-custom-templates"; - -export function getTemplates(): SavedTemplate[] { - if (typeof window === "undefined") return []; - - const data = localStorage.getItem(STORAGE_KEY); - - return data ? JSON.parse(data) : []; -} - -export function saveTemplate(template: SavedTemplate) { - const templates = getTemplates(); - - templates.push(template); - - localStorage.setItem( - STORAGE_KEY, - JSON.stringify(templates) - ); -} - -export function deleteTemplate(id: string) { - const templates = getTemplates().filter( - (t) => t.id !== id - ); - - localStorage.setItem( - STORAGE_KEY, - JSON.stringify(templates) - ); -} - -export function renameTemplate( - id: string, - newName: string -) { - const templates = getTemplates().map((t) => - t.id === id - ? { ...t, name: newName } - : t - ); - - localStorage.setItem( - STORAGE_KEY, - JSON.stringify(templates) - ); -} \ No newline at end of file