summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2025-06-25 18:46:26 +0200
committerMaze Winther <mazewinther@gmail.com>2025-06-25 18:46:26 +0200
commitba14d65605a7e0913516efcb16e89e96a9e06b4d (patch)
tree9cee43a5acf98e6e715eec91be5e50d633452f88
parent94d39dfa7e9ee38d31c052c4aec8c4cba902cd8a (diff)
parent00d7b3ba8db128207a461780efd97c83cf074bec (diff)
downloadopencut-ba14d65605a7e0913516efcb16e89e96a9e06b4d.tar.gz
Merge branch 'main' of https://github.com/mazeincoding/AppCut
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md31
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yml70
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md19
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.yml42
-rw-r--r--.github/workflows/bun-ci.yml4
-rw-r--r--apps/web/src/components/editor/media-panel.tsx26
-rw-r--r--apps/web/src/components/editor/timeline.tsx53
-rw-r--r--apps/web/src/lib/media-processing.ts15
8 files changed, 169 insertions, 91 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 85cc4b23..00000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,31 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: '[BUG] '
-labels: bug
-assignees: ''
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior:
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Screenshots**
-If applicable, add screenshots to help explain your problem.
-
-**Desktop (please complete the following information):**
- - OS: [e.g. iOS]
- - Browser [e.g. chrome, safari]
- - Version [e.g. 22]
-
-**Additional context**
-Add any other context about the problem here. \ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 00000000..c9684d1f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,70 @@
+name: Bug report
+description: Create a report to help us improve
+title: '[BUG] '
+labels: bug
+body:
+ - type: input
+ id: Platform
+ attributes:
+ label: Platform
+ description: Please enter the platform on which you encountered the bug.
+ placeholder: e.g. Windows 11, Ubuntu 14.04
+ validations:
+ required: true
+ - type: input
+ id: Browser
+ attributes:
+ label: Browser
+ description: Please enter the browser on which you encountered the bug.
+ placeholder: e.g. Chrome 137, Firefox 137, Safari 17
+ validations:
+ required: true
+ - type: textarea
+ id: current-behavior
+ attributes:
+ label: Current Behavior
+ description: A concise description of what you're experiencing.
+ validations:
+ required: true
+ - type: textarea
+ id: expected-behavior
+ attributes:
+ label: Expected Behavior
+ description: A concise description of what you expected to happen.
+ validations:
+ required: false
+ - type: dropdown
+ id: recurrence-probability
+ attributes:
+ label: Recurrence Probability
+ description: How often does this bug occur?
+ options:
+ - Always
+ - Usually
+ - Sometimes
+ - Seldom
+ default: 0
+ validations:
+ required: true
+ - type: textarea
+ id: steps-to-reproduce
+ attributes:
+ label: Steps To Reproduce
+ description: Steps to reproduce the behavior.
+ placeholder: |
+ 1. Go to '...'
+ 2. Click on '....'
+ 3. Scroll down to '....'
+ 4. See error
+ validations:
+ required: true
+ - type: textarea
+ id: additional-context
+ attributes:
+ label: Anything else?
+ description: |
+ Links? References? Anything that will give us more context about the issue you are encountering!
+
+ Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
+ validations:
+ required: false \ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index 1d528f25..00000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: '[FEATURE] '
-labels: enhancement
-assignees: ''
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here. \ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 00000000..49a00eb6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,42 @@
+name: Feature request
+description: Suggest an idea for OpenCut
+title: '[FEATURE] '
+labels: enhancement
+body:
+ - type: markdown
+ attributes:
+ value: Please make sure that no duplicated issues has already been delivered.
+ - type: textarea
+ id: problem
+ attributes:
+ label: Problem
+ placeholder: Is your feature request related to a problem? Please describe.
+ description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+ validations:
+ required: true
+ - type: textarea
+ id: solution
+ attributes:
+ label: Solution
+ placeholder: Describe the solution you'd like.
+ description: A clear and concise description of what you want to happen.
+ validations:
+ required: true
+ - type: textarea
+ id: alternative
+ attributes:
+ label: Alternative
+ placeholder: Describe alternatives you've considered.
+ description: A clear and concise description of any alternative solutions or features you've considered.
+ validations:
+ required: true
+ - type: textarea
+ id: additional-context
+ attributes:
+ label: Anything else?
+ description: |
+ Links? References? Anything that will give us more context about the issue you are encountering!
+
+ Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
+ validations:
+ required: false \ No newline at end of file
diff --git a/.github/workflows/bun-ci.yml b/.github/workflows/bun-ci.yml
index 4df6212a..34b6d516 100644
--- a/.github/workflows/bun-ci.yml
+++ b/.github/workflows/bun-ci.yml
@@ -31,13 +31,13 @@ jobs:
- name: Install Bun
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76
with:
- bun-version: 1.2.2
+ bun-version: 1.2.17
- name: Cache Bun modules
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
- key: ${{ runner.os }}-bun-${{ hashFiles('apps/web/bun.lock') }}
+ key: ${{ runner.os }}-bun-1.2.17-${{ hashFiles('apps/web/bun.lock') }}
- name: Install dependencies
working-directory: apps/web
diff --git a/apps/web/src/components/editor/media-panel.tsx b/apps/web/src/components/editor/media-panel.tsx
index f2b3f657..cdd67a86 100644
--- a/apps/web/src/components/editor/media-panel.tsx
+++ b/apps/web/src/components/editor/media-panel.tsx
@@ -17,27 +17,28 @@ export function MediaPanel() {
const { mediaItems, addMediaItem, removeMediaItem } = useMediaStore();
const fileInputRef = useRef<HTMLInputElement>(null);
const [isProcessing, setIsProcessing] = useState(false);
+ const [progress, setProgress] = useState(0);
const [searchQuery, setSearchQuery] = useState("");
const [mediaFilter, setMediaFilter] = useState("all");
const processFiles = async (files: FileList | File[]) => {
- // If no files, do nothing
- if (!files?.length) return;
-
+ if (!files || files.length === 0) return;
setIsProcessing(true);
+ setProgress(0);
try {
// Process files (extract metadata, generate thumbnails, etc.)
- const items = await processMediaFiles(files);
+ const processedItems = await processMediaFiles(files, (p) =>
+ setProgress(p)
+ );
// Add each processed media item to the store
- items.forEach((item) => {
- addMediaItem(item);
- });
+ processedItems.forEach((item) => addMediaItem(item));
} catch (error) {
- // Show error if processing fails
- console.error("File processing failed:", error);
+ // Show error toast if processing fails
+ console.error("Error processing files:", error);
toast.error("Failed to process files");
} finally {
setIsProcessing(false);
+ setProgress(0);
}
};
@@ -241,15 +242,12 @@ export function MediaPanel() {
{isProcessing ? (
<>
<Upload className="h-4 w-4 animate-spin" />
- <span className="hidden md:inline ml-2">Processing...</span>
+ <span className="hidden md:inline ml-2">{progress}%</span>
</>
) : (
<>
<Plus className="h-4 w-4" />
- <span
- className="hidden sm:inline ml-2"
- aria-label="Add file"
- >
+ <span className="hidden sm:inline ml-2" aria-label="Add file">
Add
</span>
</>
diff --git a/apps/web/src/components/editor/timeline.tsx b/apps/web/src/components/editor/timeline.tsx
index c1b8f3e8..1ecbe545 100644
--- a/apps/web/src/components/editor/timeline.tsx
+++ b/apps/web/src/components/editor/timeline.tsx
@@ -69,6 +69,7 @@ export function Timeline() {
} = usePlaybackStore();
const [isDragOver, setIsDragOver] = useState(false);
const [isProcessing, setIsProcessing] = useState(false);
+ const [progress, setProgress] = useState(0);
const [zoomLevel, setZoomLevel] = useState(1);
const dragCounterRef = useRef(0);
const timelineRef = useRef<HTMLDivElement>(null);
@@ -334,8 +335,12 @@ export function Timeline() {
} else if (e.dataTransfer.files?.length > 0) {
// Handle file drops by creating new tracks
setIsProcessing(true);
+ setProgress(0);
try {
- const processedItems = await processMediaFiles(e.dataTransfer.files);
+ const processedItems = await processMediaFiles(
+ e.dataTransfer.files,
+ (p) => setProgress(p)
+ );
for (const processedItem of processedItems) {
addMediaItem(processedItem);
const currentMediaItems = useMediaStore.getState().mediaItems;
@@ -363,6 +368,7 @@ export function Timeline() {
toast.error("Failed to process dropped files");
} finally {
setIsProcessing(false);
+ setProgress(0);
}
}
};
@@ -594,10 +600,11 @@ export function Timeline() {
<div className="w-px h-6 bg-border mx-1" />
{/* Time Display */}
- <div className="text-xs text-muted-foreground font-mono px-2"
- style={{ minWidth: '18ch', textAlign: 'center' }}
- >
- {currentTime.toFixed(1)}s / {duration.toFixed(1)}s
+ <div
+ className="text-xs text-muted-foreground font-mono px-2"
+ style={{ minWidth: "18ch", textAlign: "center" }}
+ >
+ {currentTime.toFixed(1)}s / {duration.toFixed(1)}s
</div>
{/* Test Clip Button - for debugging */}
@@ -946,14 +953,12 @@ export function Timeline() {
</>
)}
{isDragOver && (
- <div
- className="absolute left-0 right-0 border-2 border-dashed border-accent flex items-center justify-center text-muted-foreground"
- style={{
- top: `${tracks.length * 60}px`,
- height: "60px",
- }}
- >
- <div>Drop media here to add a new track</div>
+ <div className="absolute inset-0 z-20 flex items-center justify-center pointer-events-none backdrop-blur-lg">
+ <div>
+ {isProcessing
+ ? `Processing ${progress}%`
+ : "Drop media here to add to timeline"}
+ </div>
</div>
)}
</div>
@@ -1630,18 +1635,18 @@ function TimelineTrackContent({
}
if (mediaItem.type === "audio") {
- return (
- <div className="w-full h-full flex items-center gap-2">
- <div className="flex-1 min-w-0">
- <AudioWaveform
- audioUrl={mediaItem.url}
- height={24}
- className="w-full"
- />
+ return (
+ <div className="w-full h-full flex items-center gap-2">
+ <div className="flex-1 min-w-0">
+ <AudioWaveform
+ audioUrl={mediaItem.url}
+ height={24}
+ className="w-full"
+ />
+ </div>
</div>
- </div>
- );
- }
+ );
+ }
// Fallback for videos without thumbnails
return (
diff --git a/apps/web/src/lib/media-processing.ts b/apps/web/src/lib/media-processing.ts
index d241f411..daf22b34 100644
--- a/apps/web/src/lib/media-processing.ts
+++ b/apps/web/src/lib/media-processing.ts
@@ -11,11 +11,15 @@ import {
export interface ProcessedMediaItem extends Omit<MediaItem, "id"> {}
export async function processMediaFiles(
- files: FileList | File[]
+ files: FileList | File[],
+ onProgress?: (progress: number) => void
): Promise<ProcessedMediaItem[]> {
const fileArray = Array.from(files);
const processedItems: ProcessedMediaItem[] = [];
+ const total = fileArray.length;
+ let completed = 0;
+
for (const file of fileArray) {
const fileType = getFileType(file);
@@ -57,6 +61,15 @@ export async function processMediaFiles(
duration,
aspectRatio,
});
+
+ // Yield back to the event loop to keep the UI responsive
+ await new Promise((resolve) => setTimeout(resolve, 0));
+
+ completed += 1;
+ if (onProgress) {
+ const percent = Math.round((completed / total) * 100);
+ onProgress(percent);
+ }
} catch (error) {
console.error("Error processing file:", file.name, error);
toast.error(`Failed to process ${file.name}`);