diff --git a/.cursor/rules/ultracite.mdc b/.cursor/rules/ultracite.mdc index c8208f06..78aa4a29 100644 --- a/.cursor/rules/ultracite.mdc +++ b/.cursor/rules/ultracite.mdc @@ -6,7 +6,7 @@ alwaysApply: true # Project Context -Ultracite enforces strict type safety, accessibility standards, and consistent code quality for JavaScript/TypeScript projects using Biome's lightning-fast formatter and linter. +Ultracite enforces strict type safety, accessibility standards, and consistent code quality for JavaScript/TypeScript projects using Prettier's formatter. ## Key Principles diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index b6d67872..2661e182 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -17,23 +17,23 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall +- Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: -* The use of sexualized language or imagery, and sexual attention or advances of +- The use of sexualized language or imagery, and sexual attention or advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email address, +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index c9684d1f..01965d41 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug report description: Create a report to help us improve -title: '[BUG] ' +title: "[BUG] " labels: bug body: - type: input @@ -15,7 +15,7 @@ body: id: Browser attributes: label: Browser - description: Please enter the browser on which you encountered the bug. + description: Please enter the browser on which you encountered the bug. placeholder: e.g. Chrome 137, Firefox 137, Safari 17 validations: required: true @@ -67,4 +67,4 @@ body: 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 + required: false diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 49a00eb6..336e2d6a 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,6 @@ name: Feature request description: Suggest an idea for OpenCut -title: '[FEATURE] ' +title: "[FEATURE] " labels: enhancement body: - type: markdown @@ -39,4 +39,4 @@ body: 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 + required: false diff --git a/.github/SECURITY.md b/.github/SECURITY.md index f6d94c5e..1369bbab 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -25,4 +25,4 @@ Please do not report security vulnerabilities through public GitHub issues. - We will provide a detailed response within 5 business days - We will keep you updated on our progress -Thank you for helping keep OpenCut secure! \ No newline at end of file +Thank you for helping keep OpenCut secure! diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md index 892a0f7a..1df3d7bd 100644 --- a/.github/SUPPORT.md +++ b/.github/SUPPORT.md @@ -3,21 +3,25 @@ Thanks for using OpenCut! If you need help, here are your options: ## Documentation + - Check our [README](../README.md) for basic setup instructions - Review the [Contributing Guidelines](CONTRIBUTING.md) for development setup ## Issues + - **Bug reports**: Use the bug report template - **Feature requests**: Use the feature request template - **Questions**: Use GitHub Discussions for general questions ## Community + - Join our discussions on GitHub - Follow the [Code of Conduct](CODE_OF_CONDUCT.md) ## Response Times + - Issues are typically triaged within 2-3 business days - Feature requests may take longer to evaluate - Security issues are handled with priority -We appreciate your patience and contributions to making OpenCut better! \ No newline at end of file +We appreciate your patience and contributions to making OpenCut better! diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 5d6e71f2..77e361d1 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -3,15 +3,18 @@ applyTo: "**/*.{ts,tsx,js,jsx}" --- # Project Context + Ultracite enforces strict type safety, accessibility standards, and consistent code quality for JavaScript/TypeScript projects using Biome's lightning-fast formatter and linter. ## Key Principles + - Zero configuration required - Subsecond performance - Maximum type safety - AI-friendly code generation ## Before Writing Code + 1. Analyze existing patterns in the codebase 2. Consider edge cases and error scenarios 3. Follow the rules below strictly @@ -20,6 +23,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c ## Rules ### Accessibility (a11y) + - Don't use `accessKey` attribute on any HTML element. - Don't set `aria-hidden="true"` on focusable elements. - Don't add ARIA roles, states, and properties to elements that don't support them. @@ -56,6 +60,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c - Use correct ISO language/country codes for the `lang` attribute. ### Code Complexity and Quality + - Don't use consecutive spaces in regular expression literals. - Don't use the `arguments` object. - Don't use primitive type aliases or misleading types. @@ -111,6 +116,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c - Don't use literal numbers that lose precision. ### React and JSX Best Practices + - Don't use the return value of React.render. - Make sure all dependencies are correctly specified in React hooks. - Make sure all React hooks are called from the top level of component functions. @@ -129,6 +135,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c - Watch out for possible "wrong" semicolons inside JSX elements. ### Correctness and Safety + - Don't assign a value to itself. - Don't return a value from a setter. - Don't compare expressions that modify string case with non-compliant values. @@ -153,7 +160,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c - Don't use bitwise operators. - Don't use expressions where the operation doesn't change the value. - Make sure Promise-like statements are handled appropriately. -- Don't use __dirname and __filename in the global scope. +- Don't use **dirname and **filename in the global scope. - Prevent import cycles. - Don't use configured elements. - Don't hardcode sensitive data like API keys and tokens. @@ -184,6 +191,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c - Don't use `target="_blank"` without `rel="noopener"`. ### TypeScript Best Practices + - Don't use TypeScript enums. - Don't export imported variables. - Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions. @@ -208,6 +216,7 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c - Use the namespace keyword instead of the module keyword to declare TypeScript namespaces. ### Style and Consistency + - Don't use global `eval()`. - Don't use callbacks in asynchronous tests and hooks. - Don't use negation in `if` statements that have `else` clauses. @@ -295,30 +304,34 @@ Ultracite enforces strict type safety, accessibility standards, and consistent c - Make sure to use the "use strict" directive in script files. ### Next.js Specific Rules + - Don't use `` elements in Next.js projects. - Don't use `` elements in Next.js projects. -- Don't import next/document outside of pages/_document.jsx in Next.js projects. -- Don't use the next/head module in pages/_document.js on Next.js projects. +- Don't import next/document outside of pages/\_document.jsx in Next.js projects. +- Don't use the next/head module in pages/\_document.js on Next.js projects. ### Testing Best Practices + - Don't use export or module.exports in test files. - Don't use focused tests. - Make sure the assertion function, like expect, is placed inside an it() function call. - Don't use disabled tests. ## Common Tasks + - `npx ultracite init` - Initialize Ultracite in your project - `npx ultracite format` - Format and fix code automatically - `npx ultracite lint` - Check for issues without fixing ## Example: Error Handling + ```typescript // βœ… Good: Comprehensive error handling try { const result = await fetchData(); return { success: true, data: result }; } catch (error) { - console.error('API call failed:', error); + console.error("API call failed:", error); return { success: false, error: error.message }; } @@ -328,4 +341,4 @@ try { } catch (e) { console.log(e); } -``` \ No newline at end of file +``` diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b7686c4b..b9664c76 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -24,9 +24,10 @@ Please describe the tests that you ran to verify your changes. Provide instructi - [ ] Test B **Test Configuration**: -* Node version: -* Browser (if applicable): -* Operating System: + +- Node version: +- Browser (if applicable): +- Operating System: ## Screenshots (if applicable) @@ -46,4 +47,4 @@ Add screenshots to help explain your changes. ## Additional context -Add any other context about the pull request here. +Add any other context about the pull request here. diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..4628520e --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +.git +apps/web/.next/ +apps/web/public/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 8b0bc4ef..b4bfed35 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,3 @@ { "plugins": ["prettier-plugin-tailwindcss"] -} \ No newline at end of file +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 8eff0c83..dbab3048 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,17 +1,16 @@ { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "[javascript][typescript][javascriptreact][typescriptreact][json][jsonc][css][graphql]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "typescript.tsdk": "node_modules/typescript/lib", - "editor.formatOnSave": true, - "editor.formatOnPaste": true, - "emmet.showExpandedAbbreviation": "never", - "[typescriptreact]": { - "editor.defaultFormatter": "vscode.typescript-language-features" - }, - "[typescript]": { - "editor.defaultFormatter": "vscode.typescript-language-features" - } + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[javascript][typescript][javascriptreact][typescriptreact][json][jsonc][css][graphql]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "typescript.tsdk": "node_modules/typescript/lib", + "editor.formatOnSave": true, + "editor.formatOnPaste": true, + "emmet.showExpandedAbbreviation": "never", + "[typescriptreact]": { + "editor.defaultFormatter": "vscode.typescript-language-features" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" } - \ No newline at end of file +} diff --git a/AGENTS.md b/AGENTS.md index ded7f32a..7cbe7736 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -32,16 +32,17 @@ import { useEditor } from '@/hooks/use-editor'; function MyComponent() { const editor = useEditor(); const tracks = editor.timeline.getTracks(); - + // Call methods editor.timeline.addTrack({ type: 'media' }); - + // Display data (auto re-renders on changes) return
{tracks.length} tracks
; } ``` The hook: + - Returns the singleton instance - Subscribes to all manager changes - Automatically re-renders when state changes @@ -52,10 +53,10 @@ The hook: ```typescript // In utilities, event handlers, or non-React code -import { EditorCore } from '@/core'; +import { EditorCore } from "@/core"; const editor = EditorCore.getInstance(); -await editor.export({ format: 'mp4', quality: 'high' }); +await editor.export({ format: "mp4", quality: "high" }); ``` ## Actions System @@ -65,6 +66,7 @@ Actions are the trigger layer for user-initiated operations. The single source o **To add a new action:** 1. Add it to `ACTIONS` in `@/lib/actions/definitions.ts`: + ```typescript export const ACTIONS = { "my-action": { @@ -73,14 +75,19 @@ export const ACTIONS = { defaultShortcuts: ["ctrl+m"], }, // ... -} +}; ``` 2. Add handler in `@/hooks/use-editor-actions.ts`: + ```typescript -useActionHandler("my-action", () => { - // implementation -}, undefined); +useActionHandler( + "my-action", + () => { + // implementation + }, + undefined, +); ``` **In components, use `invokeAction()` for user-triggered operations:** @@ -102,6 +109,7 @@ Direct `editor.xxx()` calls are for internal use (commands, tests, complex multi Commands handle undo/redo. They live in `@/lib/commands/` organized by domain (timeline, media, scene). Each command extends `Command` from `@/lib/commands/base-command` and implements: + - `execute()` - saves current state, then does the mutation - `undo()` - restores the saved state diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 1594a6a6..00000000 --- a/TODO.md +++ /dev/null @@ -1,6 +0,0 @@ -[x] Delete all stores we can -[x] Create commands for each action -[x] Finish timeline store -[x] Migrate final timeline store to manager -[x] Delete timeline store -[ ] Update usage of all stores to use the new managers \ No newline at end of file diff --git a/apps/web/src/app/api/sounds/search/route.ts b/apps/web/src/app/api/sounds/search/route.ts index a477c9db..b7356680 100644 --- a/apps/web/src/app/api/sounds/search/route.ts +++ b/apps/web/src/app/api/sounds/search/route.ts @@ -96,7 +96,7 @@ function buildSortParameter({ query, sort }: { query?: string; sort: string }) { function applyEffectsFilters({ params, min_rating, - commercial_only + commercial_only, }: { params: URLSearchParams; min_rating: number; @@ -108,17 +108,19 @@ function applyEffectsFilters({ if (commercial_only) { params.append( "filter", - 'license:("Attribution" OR "Creative Commons 0" OR "Attribution Noncommercial" OR "Attribution Commercial")' + 'license:("Attribution" OR "Creative Commons 0" OR "Attribution Noncommercial" OR "Attribution Commercial")', ); } params.append( "filter", - "tag:sound-effect OR tag:sfx OR tag:foley OR tag:ambient OR tag:nature OR tag:mechanical OR tag:electronic OR tag:impact OR tag:whoosh OR tag:explosion" + "tag:sound-effect OR tag:sfx OR tag:foley OR tag:ambient OR tag:nature OR tag:mechanical OR tag:electronic OR tag:impact OR tag:whoosh OR tag:explosion", ); } -function transformFreesoundResult(result: z.infer) { +function transformFreesoundResult( + result: z.infer, +) { return { id: result.id, name: result.name, @@ -169,7 +171,7 @@ export async function GET(request: NextRequest) { error: "Invalid parameters", details: validationResult.error.flatten().fieldErrors, }, - { status: 400 } + { status: 400 }, ); } @@ -190,7 +192,7 @@ export async function GET(request: NextRequest) { message: "Song search functionality is coming soon. Try searching for sound effects instead.", }, - { status: 501 } + { status: 501 }, ); } @@ -220,7 +222,7 @@ export async function GET(request: NextRequest) { console.error("Freesound API error:", response.status, errorText); return NextResponse.json( { error: "Failed to search sounds" }, - { status: response.status } + { status: response.status }, ); } @@ -230,11 +232,11 @@ export async function GET(request: NextRequest) { if (!freesoundValidation.success) { console.error( "Invalid Freesound API response:", - freesoundValidation.error + freesoundValidation.error, ); return NextResponse.json( { error: "Invalid response from Freesound API" }, - { status: 502 } + { status: 502 }, ); } @@ -259,11 +261,11 @@ export async function GET(request: NextRequest) { if (!responseValidation.success) { console.error( "Invalid API response structure:", - responseValidation.error + responseValidation.error, ); return NextResponse.json( { error: "Internal response formatting error" }, - { status: 500 } + { status: 500 }, ); } @@ -272,7 +274,7 @@ export async function GET(request: NextRequest) { console.error("Error searching sounds:", error); return NextResponse.json( { error: "Internal server error" }, - { status: 500 } + { status: 500 }, ); } -} \ No newline at end of file +} diff --git a/apps/web/src/app/base-page.tsx b/apps/web/src/app/base-page.tsx index 48303e8e..38eca161 100644 --- a/apps/web/src/app/base-page.tsx +++ b/apps/web/src/app/base-page.tsx @@ -30,7 +30,7 @@ export function BasePage({
-
+

{post.title}

{post.description}

diff --git a/apps/web/src/app/projects/page.tsx b/apps/web/src/app/projects/page.tsx index 7bba1023..2c62b554 100644 --- a/apps/web/src/app/projects/page.tsx +++ b/apps/web/src/app/projects/page.tsx @@ -190,7 +190,7 @@ export default function ProjectsPage() { )}
-
+

@@ -419,16 +419,18 @@ function ProjectCard({ const cardContent = (
{isSelectionMode && ( -
-
+
+
@@ -462,7 +464,7 @@ function ProjectCard({
-

+

{project.name}

{!isSelectionMode && ( @@ -475,10 +477,11 @@ function ProjectCard({ aria-label="project options" variant="text" size="sm" - className={`ml-2 size-6 shrink-0 p-0 transition-all ${isDropdownOpen - ? "opacity-100" - : "opacity-0 group-hover:opacity-100" - }`} + className={`ml-2 size-6 shrink-0 p-0 transition-all ${ + isDropdownOpen + ? "opacity-100" + : "opacity-0 group-hover:opacity-100" + }`} onClick={(event) => event.preventDefault()} >