-
Notifications
You must be signed in to change notification settings - Fork 4.2k
feat: add panel presets #514
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add panel presets #514
Conversation
|
@enkeii64 is attempting to deploy a commit to the OpenCut OSS Team on Vercel. A member of the Team first needs to authorize it. |
👷 Deploy request for appcut pending review.Visit the deploys page to approve it
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis update introduces a panel layout preset system to the web editor. The panel store is refactored to support multiple named presets, each with its own size configurations and reset logic. The editor UI now conditionally renders layouts based on the active preset. A new UI component allows users to select and reset panel presets. Additional changes include minor formatting improvements and the integration of the preset selector into the editor header. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant PanelPresetSelector
participant PanelStore
participant Editor
User->>PanelPresetSelector: Selects a panel preset or resets it
PanelPresetSelector->>PanelStore: setActivePreset(preset) or resetPreset(preset)
PanelStore-->>Editor: Updates activePreset and panel sizes
Editor->>Editor: Rerenders layout based on activePreset
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Suggested reviewers
Poem
✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/web/src/components/panel-preset-selector.tsx (1)
77-86: Consider adding keyboard support for the reset button.While the button is properly configured with hover states and title attribute, consider adding keyboard event handlers for better accessibility.
<Button variant="secondary" size="icon" className="h-6 w-6 shrink-0 opacity-60 hover:opacity-100" onClick={(e) => handleResetPreset(preset, e)} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + handleResetPreset(preset, e); + } + }} title={`Reset ${PRESET_LABELS[preset]} preset`} >apps/web/src/app/editor/[project_id]/page.tsx (1)
164-164: Minor inconsistency in gap values.The gap values vary slightly between layouts (0.18rem vs 0.19rem). Consider standardizing these values for consistency.
- className="h-full w-full gap-[0.18rem] px-3 pb-3" + className="h-full w-full gap-[0.19rem] px-3 pb-3"Also applies to: 185-185, 238-238, 247-247, 258-258, 313-313, 322-322, 333-333, 388-388, 400-400
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
apps/web/src/app/editor/[project_id]/page.tsx(2 hunks)apps/web/src/components/editor-header.tsx(2 hunks)apps/web/src/components/editor/audio-waveform.tsx(3 hunks)apps/web/src/components/editor/media-panel/tabbar.tsx(1 hunks)apps/web/src/components/editor/preview-panel.tsx(1 hunks)apps/web/src/components/keyboard-shortcuts-help.tsx(1 hunks)apps/web/src/components/panel-preset-selector.tsx(1 hunks)apps/web/src/components/ui/editable-timecode.tsx(1 hunks)apps/web/src/data/colors/syntax-ui.tsx(1 hunks)apps/web/src/stores/panel-store.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{jsx,tsx}
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
**/*.{jsx,tsx}: Don't useaccessKeyattribute on any HTML element.
Don't setaria-hidden="true"on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Don't use distracting elements like<marquee>or<blink>.
Only use thescopeprop on<th>elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assigntabIndexto non-interactive HTML elements.
Don't use positive integers fortabIndexproperty.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include atitleelement for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
AssigntabIndexto non-interactive HTML elements witharia-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include atypeattribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden).
Always include alangattribute on the html element.
Always include atitleattribute for iframe elements.
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress.
AccompanyonMouseOver/onMouseOutwithonFocus/onBlur.
Include caption tracks for audio and video elements.
Use semantic elements instead of role attributes in JSX.
Make sure all anchors are valid and navigable.
Ensure all ARIA properties (aria-*) are valid.
Use valid, non-abstract ARIA roles for elements with...
Files:
apps/web/src/data/colors/syntax-ui.tsxapps/web/src/components/editor/audio-waveform.tsxapps/web/src/components/editor-header.tsxapps/web/src/components/panel-preset-selector.tsxapps/web/src/components/ui/editable-timecode.tsxapps/web/src/components/editor/preview-panel.tsxapps/web/src/components/editor/media-panel/tabbar.tsxapps/web/src/components/keyboard-shortcuts-help.tsxapps/web/src/app/editor/[project_id]/page.tsx
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
**/*.{js,jsx,ts,tsx}: Don't use consecutive spaces in regular expression literals.
Don't use theargumentsobject.
Don't use the comma operator.
Don't write functions that exceed a given Cognitive Complexity score.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use uselessthisaliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names that aren't base 10 or use underscore separators.
Remove redundant terms from logical expressions.
Use while loops instead of for loops when you don't need initializer and update expressions.
Don't reassign const variables....
Files:
apps/web/src/data/colors/syntax-ui.tsxapps/web/src/components/editor/audio-waveform.tsxapps/web/src/components/editor-header.tsxapps/web/src/components/panel-preset-selector.tsxapps/web/src/components/ui/editable-timecode.tsxapps/web/src/components/editor/preview-panel.tsxapps/web/src/components/editor/media-panel/tabbar.tsxapps/web/src/components/keyboard-shortcuts-help.tsxapps/web/src/stores/panel-store.tsapps/web/src/app/editor/[project_id]/page.tsx
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't return a value from a function with the return type 'void'.
Don't use the TypeScript directive @ts-ignore.
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.
Don't use TypeScript namespaces.
Don't use non-null assertions with the!postfix operator.
Don't use parameter properties in class constructors.
Don't use user-defined types.
Useas constinstead of literal types and type annotations.
Use eitherT[]orArray<T>consistently.
Initialize each enum member value explicitly.
Useexport typefor types.
Useimport typefor types.
Make sure all enum members are literal values.
Don't use TypeScript const enum.
Don't declare empty interfaces.
Don't let variables evolve into any type through reassignments.
Don't use the any type.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use implicit any type on variable declarations.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Use consistent accessibility modifiers on class properties and methods.
Use function types instead of object types with call signatures.
Don't use void type outside of generic or return types.
**/*.{ts,tsx}: 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.
Don't use TypeScript namespaces.
Don't use non-null assertions with the!postfix operator.
Don't use parameter properties in class constructors.
Don't use user-defined types.
Useas constinstead of literal types and...
Files:
apps/web/src/data/colors/syntax-ui.tsxapps/web/src/components/editor/audio-waveform.tsxapps/web/src/components/editor-header.tsxapps/web/src/components/panel-preset-selector.tsxapps/web/src/components/ui/editable-timecode.tsxapps/web/src/components/editor/preview-panel.tsxapps/web/src/components/editor/media-panel/tabbar.tsxapps/web/src/components/keyboard-shortcuts-help.tsxapps/web/src/stores/panel-store.tsapps/web/src/app/editor/[project_id]/page.tsx
🧠 Learnings (44)
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use irregular whitespace characters....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use irregular whitespace characters.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsxapps/web/src/components/editor/audio-waveform.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't export empty modules that don't change anything....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't export empty modules that don't change anything.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsxapps/web/src/components/editor/audio-waveform.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : use standard constants instead of approximated literals....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use standard constants instead of approximated literals.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsxapps/web/src/components/ui/editable-timecode.tsxapps/web/src/components/editor/preview-panel.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use unnecessary escapes in string literals....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use unnecessary escapes in string literals.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't compare things where both sides are exactly the same....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.403Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't compare things where both sides are exactly the same.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use unnecessary labels....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use unnecessary labels.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsxapps/web/src/components/editor/audio-waveform.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use unnecessary escape sequences in regular expression liter...
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use unnecessary escape sequences in regular expression literals.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsx
📚 Learning: in tailwind css v4, gradient utilities have been completely redesigned. the new system includes `bg-...
Learnt from: brandonmcconnell
PR: OpenCut-app/OpenCut#498
File: apps/web/src/components/editor/media-panel/views/media.tsx:170-173
Timestamp: 2025-07-30T23:20:57.999Z
Learning: In Tailwind CSS v4, gradient utilities have been completely redesigned. The new system includes `bg-linear-*` for linear gradients, `bg-radial-*` for radial gradients, and `bg-conic-*` for conic gradients, with support for color interpolation modifiers like `/oklch` and `/srgb`.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsx
📚 Learning: tailwind css v4 introduces new `bg-linear-to-*` gradient utilities including `bg-linear-to-br`, `bg-...
Learnt from: brandonmcconnell
PR: OpenCut-app/OpenCut#498
File: apps/web/src/app/blog/page.tsx:31-32
Timestamp: 2025-07-30T23:20:54.822Z
Learning: Tailwind CSS v4 introduces new `bg-linear-to-*` gradient utilities including `bg-linear-to-br`, `bg-linear-to-tr`, `bg-linear-to-r`, `bg-linear-to-b`, `bg-linear-to-bl`, `bg-linear-to-l`, and `bg-linear-to-t`. These replace or complement the previous `bg-gradient-to-*` utilities from v3 and are part of v4's expanded gradient API that also includes angle-based gradients, gradient interpolation modifiers, and new conic/radial gradient utilities.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsx
📚 Learning: tailwind css v4 introduces new gradient utilities including `bg-linear-to-br`, `bg-linear-to-tr`, `b...
Learnt from: brandonmcconnell
PR: OpenCut-app/OpenCut#498
File: apps/web/src/components/editor/media-panel/views/media.tsx:170-173
Timestamp: 2025-07-30T23:20:57.999Z
Learning: Tailwind CSS v4 introduces new gradient utilities including `bg-linear-to-br`, `bg-linear-to-tr`, `bg-linear-to-r`, etc., replacing the previous `bg-gradient-to-*` syntax from v3. These new utilities provide the same gradient functionality with updated naming conventions.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsx
📚 Learning: tailwind css v4 introduces new gradient utilities including `bg-linear-to-br`, `bg-linear-to-tr`, `b...
Learnt from: brandonmcconnell
PR: OpenCut-app/OpenCut#498
File: apps/web/src/app/blog/page.tsx:31-32
Timestamp: 2025-07-30T23:20:54.822Z
Learning: Tailwind CSS v4 introduces new gradient utilities including `bg-linear-to-br`, `bg-linear-to-tr`, `bg-linear-to-r`, etc. as part of their updated gradient API, replacing or complementing the previous `bg-gradient-to-*` utilities from v3.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsx
📚 Learning: tailwind css v4 replaces the `bg-gradient-to-*` utilities from v3 with new `bg-linear-to-*` utilitie...
Learnt from: brandonmcconnell
PR: OpenCut-app/OpenCut#498
File: apps/web/src/components/editor/media-panel/views/media.tsx:170-173
Timestamp: 2025-07-30T23:20:57.999Z
Learning: Tailwind CSS v4 replaces the `bg-gradient-to-*` utilities from v3 with new `bg-linear-to-*` utilities (e.g., `bg-linear-to-br`, `bg-linear-to-tr`, `bg-linear-to-r`). These new utilities provide enhanced gradient control including explicit angles, color interpolation modes, and better fallback support.
Applied to files:
apps/web/src/data/colors/syntax-ui.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : use `string.trimstart()` and `string.trimend()` over `string.triml...
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use `String.trimStart()` and `String.trimEnd()` over `String.trimLeft()` and `String.trimRight()`.
Applied to files:
apps/web/src/components/editor/audio-waveform.tsxapps/web/src/components/editor/preview-panel.tsx
📚 Learning: applies to **/*.{jsx,tsx} : don't use unnecessary fragments....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{jsx,tsx} : Don't use unnecessary fragments.
Applied to files:
apps/web/src/components/editor/audio-waveform.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use consecutive spaces in regular expression literals....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use consecutive spaces in regular expression literals.
Applied to files:
apps/web/src/components/editor/audio-waveform.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use useless undefined....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use useless undefined.
Applied to files:
apps/web/src/components/editor/audio-waveform.tsx
📚 Learning: the file apps/web/src/components/editor/media-panel/views/media.tsx uses "use client" directive, mak...
Learnt from: khanguyen74
PR: OpenCut-app/OpenCut#466
File: apps/web/src/components/editor/media-panel/views/media.tsx:47-52
Timestamp: 2025-07-26T21:07:57.582Z
Learning: The file apps/web/src/components/editor/media-panel/views/media.tsx uses "use client" directive, making it client-only code where window object is always available, so SSR safety checks are not needed.
Applied to files:
apps/web/src/components/editor-header.tsxapps/web/src/components/panel-preset-selector.tsxapps/web/src/components/ui/editable-timecode.tsxapps/web/src/components/editor/preview-panel.tsxapps/web/src/components/editor/media-panel/tabbar.tsxapps/web/src/app/editor/[project_id]/page.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't have unused imports....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't have unused imports.
Applied to files:
apps/web/src/components/editor-header.tsx
📚 Learning: applies to **/*.{jsx,tsx} : use `<>...` instead of `...`....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{jsx,tsx} : Use `<>...</>` instead of `<Fragment>...</Fragment>`.
Applied to files:
apps/web/src/components/editor-header.tsxapps/web/src/components/ui/editable-timecode.tsx
📚 Learning: applies to **/*.{jsx,tsx} : make sure anchors have content that's accessible to screen readers....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{jsx,tsx} : Make sure anchors have content that's accessible to screen readers.
Applied to files:
apps/web/src/components/editor-header.tsx
📚 Learning: applies to **/*.{jsx,tsx} : use semantic elements instead of role attributes in jsx....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{jsx,tsx} : Use semantic elements instead of role attributes in JSX.
Applied to files:
apps/web/src/components/panel-preset-selector.tsxapps/web/src/components/ui/editable-timecode.tsx
📚 Learning: applies to **/*.{ts,tsx} : don't use primitive type aliases or misleading types....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{ts,tsx} : Don't use primitive type aliases or misleading types.
Applied to files:
apps/web/src/components/ui/editable-timecode.tsx
📚 Learning: applies to **/*.{ts,tsx} : use `as const` instead of literal types and type annotations....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{ts,tsx} : Use `as const` instead of literal types and type annotations.
Applied to files:
apps/web/src/components/ui/editable-timecode.tsx
📚 Learning: applies to **/*.{jsx,tsx} : don't assign to react component props....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{jsx,tsx} : Don't assign to React component props.
Applied to files:
apps/web/src/components/ui/editable-timecode.tsx
📚 Learning: applies to **/*.{jsx,tsx} : don't use event handlers on non-interactive elements....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{jsx,tsx} : Don't use event handlers on non-interactive elements.
Applied to files:
apps/web/src/components/ui/editable-timecode.tsx
📚 Learning: applies to **/*.{jsx,tsx} : make elements with interactive roles and handlers focusable....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{jsx,tsx} : Make elements with interactive roles and handlers focusable.
Applied to files:
apps/web/src/components/ui/editable-timecode.tsxapps/web/src/components/editor/media-panel/tabbar.tsx
📚 Learning: applies to **/*.{jsx,tsx} : accompany `onmouseover`/`onmouseout` with `onfocus`/`onblur`....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{jsx,tsx} : Accompany `onMouseOver`/`onMouseOut` with `onFocus`/`onBlur`.
Applied to files:
apps/web/src/components/ui/editable-timecode.tsxapps/web/src/components/editor/media-panel/tabbar.tsxapps/web/src/components/keyboard-shortcuts-help.tsx
📚 Learning: applies to **/*.{jsx,tsx} : don't use dangerous jsx props....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{jsx,tsx} : Don't use dangerous JSX props.
Applied to files:
apps/web/src/components/ui/editable-timecode.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use expressions where the operation doesn't change the value...
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use expressions where the operation doesn't change the value.
Applied to files:
apps/web/src/components/editor/preview-panel.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use literal numbers that lose precision....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use literal numbers that lose precision.
Applied to files:
apps/web/src/components/editor/preview-panel.tsx
📚 Learning: applies to **/*.{jsx,tsx} : make sure all anchors are valid and navigable....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{jsx,tsx} : Make sure all anchors are valid and navigable.
Applied to files:
apps/web/src/components/editor/preview-panel.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use `math.min` and `math.max` to clamp values when the resul...
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use `Math.min` and `Math.max` to clamp values when the result is constant.
Applied to files:
apps/web/src/components/editor/preview-panel.tsx
📚 Learning: applies to **/*.{jsx,tsx} : assign `tabindex` to non-interactive html elements with `aria-activedesc...
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{jsx,tsx} : Assign `tabIndex` to non-interactive HTML elements with `aria-activedescendant`.
Applied to files:
apps/web/src/components/editor/media-panel/tabbar.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use nested ternary expressions....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use nested ternary expressions.
Applied to files:
apps/web/src/components/editor/media-panel/tabbar.tsxapps/web/src/components/keyboard-shortcuts-help.tsx
📚 Learning: applies to **/*.{jsx,tsx} : don't assign `tabindex` to non-interactive html elements....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{jsx,tsx} : Don't assign `tabIndex` to non-interactive HTML elements.
Applied to files:
apps/web/src/components/editor/media-panel/tabbar.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use ternary operators when simpler alternatives exist....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use ternary operators when simpler alternatives exist.
Applied to files:
apps/web/src/components/editor/media-panel/tabbar.tsxapps/web/src/components/keyboard-shortcuts-help.tsx
📚 Learning: applies to **/*.{jsx,tsx} : don't use positive integers for `tabindex` property....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{jsx,tsx} : Don't use positive integers for `tabIndex` property.
Applied to files:
apps/web/src/components/editor/media-panel/tabbar.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : use assignment operator shorthand where possible....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use assignment operator shorthand where possible.
Applied to files:
apps/web/src/components/keyboard-shortcuts-help.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : use concise optional chaining instead of chained logical expressio...
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Use concise optional chaining instead of chained logical expressions.
Applied to files:
apps/web/src/components/keyboard-shortcuts-help.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : remove redundant terms from logical expressions....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Remove redundant terms from logical expressions.
Applied to files:
apps/web/src/components/keyboard-shortcuts-help.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use duplicate conditions in if-else-if chains....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use duplicate conditions in if-else-if chains.
Applied to files:
apps/web/src/components/keyboard-shortcuts-help.tsx
📚 Learning: applies to **/*.{js,jsx,ts,tsx} : don't use unnecessary boolean casts....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Don't use unnecessary boolean casts.
Applied to files:
apps/web/src/components/keyboard-shortcuts-help.tsx
📚 Learning: applies to **/*.{jsx,tsx} : make static elements with click handlers use a valid role attribute....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{jsx,tsx} : Make static elements with click handlers use a valid role attribute.
Applied to files:
apps/web/src/components/keyboard-shortcuts-help.tsx
📚 Learning: applies to **/*.{jsx,tsx} : accompany `onclick` with at least one of: `onkeyup`, `onkeydown`, or `on...
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .cursor/rules/ultracite.mdc:0-0
Timestamp: 2025-07-27T22:15:27.748Z
Learning: Applies to **/*.{jsx,tsx} : Accompany `onClick` with at least one of: `onKeyUp`, `onKeyDown`, or `onKeyPress`.
Applied to files:
apps/web/src/components/keyboard-shortcuts-help.tsx
🔇 Additional comments (15)
apps/web/src/components/editor/audio-waveform.tsx (1)
23-23: LGTM! Clean whitespace removal.The removal of trailing whitespace-only lines improves code consistency without affecting functionality.
Also applies to: 93-93, 114-114, 117-117, 120-120
apps/web/src/data/colors/syntax-ui.tsx (1)
1-32: LGTM! Improved readability with logical grouping.The added blank lines between gradient color groups enhance code organization and readability.
apps/web/src/components/ui/editable-timecode.tsx (1)
1-137: LGTM! Consistent formatting applied.The file has been reformatted for consistency without any functional changes.
apps/web/src/stores/panel-store.ts (3)
4-43: Well-structured preset configuration system!The type definitions and preset configurations provide a clean foundation for the panel layout feature. The default size values appear reasonable for each preset's intended use case.
81-145: Consistent state management pattern for panel resizing.The setter methods properly maintain both current sizes and per-preset custom sizes, ensuring user adjustments persist when switching between presets.
148-205: Robust preset switching and reset logic.The implementation correctly:
- Saves current customizations before switching presets
- Applies saved customizations when loading a preset
- Uses
resetCounterto force UI updates when resetting- Provides a clean way to retrieve current sizes
apps/web/src/components/editor/media-panel/tabbar.tsx (1)
80-82: LGTM! Improved readability of conditional styling.The multi-line format makes the ternary expression more readable while maintaining the same logic.
apps/web/src/components/editor-header.tsx (2)
32-32: LGTM!The import statement correctly references the new panel preset selector component.
151-151: Good placement of the panel preset selector.The component is appropriately positioned as the first item in the navigation container, making it easily accessible to users.
apps/web/src/components/keyboard-shortcuts-help.tsx (1)
96-98: LGTM!The ternary expression formatting is cleaner and more concise while maintaining the same logic.
apps/web/src/components/editor/preview-panel.tsx (1)
351-368: Good clarification of order of operations.The added parentheses make the calculation more explicit by ensuring the conditional expression is evaluated before the division operation. While JavaScript's operator precedence would have handled this correctly anyway, the explicit grouping improves code readability.
apps/web/src/components/panel-preset-selector.tsx (2)
1-27: Well-structured component setup.Good organization with clear constant definitions for preset labels and descriptions. The use of Record types ensures type safety for all preset values.
35-38: Correct event propagation handling.Good practice to stop propagation on the reset button click to prevent triggering the parent dropdown item's onClick handler.
apps/web/src/app/editor/[project_id]/page.tsx (2)
33-35: Good state management integration.Properly destructuring the new activePreset and resetCounter states from the panel store to support the preset functionality.
161-161: Good use of key prop for proper remounting.The key prop correctly includes both
activePresetandresetCounterto ensure panels are properly remounted when switching presets or resetting, which preserves the expected behavior.Also applies to: 236-236, 311-311, 386-386
| {activePreset === "media" ? ( | ||
| <ResizablePanelGroup | ||
| key={`media-${activePreset}-${resetCounter}`} | ||
| direction="horizontal" | ||
| className="h-full w-full gap-[0.18rem] px-3 pb-3" | ||
| > | ||
| {/* Main content area */} | ||
| <ResizablePanelGroup | ||
| direction="horizontal" | ||
| className="h-full w-full gap-[0.19rem] px-3" | ||
| <ResizablePanel | ||
| defaultSize={toolsPanel} | ||
| minSize={15} | ||
| maxSize={40} | ||
| onResize={setToolsPanel} | ||
| className="min-w-0 rounded-sm" | ||
| > | ||
| <MediaPanel /> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| <ResizablePanel | ||
| defaultSize={100 - toolsPanel} | ||
| minSize={60} | ||
| className="min-w-0 min-h-0" | ||
| > | ||
| {/* Tools Panel */} | ||
| <ResizablePanel | ||
| defaultSize={toolsPanel} | ||
| minSize={15} | ||
| maxSize={40} | ||
| onResize={setToolsPanel} | ||
| className="min-w-0 rounded-sm" | ||
| <ResizablePanelGroup | ||
| direction="vertical" | ||
| className="h-full w-full gap-[0.18rem]" | ||
| > | ||
| <MediaPanel /> | ||
| </ResizablePanel> | ||
| <ResizablePanel | ||
| defaultSize={mainContent} | ||
| minSize={30} | ||
| maxSize={85} | ||
| onResize={setMainContent} | ||
| className="min-h-0" | ||
| > | ||
| <ResizablePanelGroup | ||
| direction="horizontal" | ||
| className="h-full w-full gap-[0.19rem]" | ||
| > | ||
| <ResizablePanel | ||
| defaultSize={previewPanel} | ||
| minSize={30} | ||
| onResize={setPreviewPanel} | ||
| className="min-w-0 min-h-0 flex-1" | ||
| > | ||
| <PreviewPanel /> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
| <ResizableHandle withHandle /> | ||
|
|
||
| {/* Preview Area */} | ||
| <ResizablePanel | ||
| defaultSize={previewPanel} | ||
| minSize={30} | ||
| onResize={setPreviewPanel} | ||
| className="min-w-0 min-h-0 flex-1" | ||
| <ResizablePanel | ||
| defaultSize={propertiesPanel} | ||
| minSize={15} | ||
| maxSize={40} | ||
| onResize={setPropertiesPanel} | ||
| className="min-w-0" | ||
| > | ||
| <PropertiesPanel /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| <ResizablePanel | ||
| defaultSize={timeline} | ||
| minSize={15} | ||
| maxSize={70} | ||
| onResize={setTimeline} | ||
| className="min-h-0" | ||
| > | ||
| <Timeline /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| ) : activePreset === "inspector" ? ( | ||
| <ResizablePanelGroup | ||
| key={`inspector-${activePreset}-${resetCounter}`} | ||
| direction="horizontal" | ||
| className="h-full w-full gap-[0.18rem] px-3 pb-3" | ||
| > | ||
| <ResizablePanel | ||
| defaultSize={100 - propertiesPanel} | ||
| minSize={60} | ||
| className="min-w-0 min-h-0" | ||
| > | ||
| <ResizablePanelGroup | ||
| direction="vertical" | ||
| className="h-full w-full gap-[0.18rem]" | ||
| > | ||
| <PreviewPanel /> | ||
| </ResizablePanel> | ||
| <ResizablePanel | ||
| defaultSize={mainContent} | ||
| minSize={30} | ||
| maxSize={85} | ||
| onResize={setMainContent} | ||
| className="min-h-0" | ||
| > | ||
| <ResizablePanelGroup | ||
| direction="horizontal" | ||
| className="h-full w-full gap-[0.19rem]" | ||
| > | ||
| <ResizablePanel | ||
| defaultSize={toolsPanel} | ||
| minSize={15} | ||
| maxSize={40} | ||
| onResize={setToolsPanel} | ||
| className="min-w-0 rounded-sm" | ||
| > | ||
| <MediaPanel /> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
| <ResizableHandle withHandle /> | ||
|
|
||
| <ResizablePanel | ||
| defaultSize={propertiesPanel} | ||
| minSize={15} | ||
| maxSize={40} | ||
| onResize={setPropertiesPanel} | ||
| className="min-w-0" | ||
| <ResizablePanel | ||
| defaultSize={previewPanel} | ||
| minSize={30} | ||
| onResize={setPreviewPanel} | ||
| className="min-w-0 min-h-0 flex-1" | ||
| > | ||
| <PreviewPanel /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| <ResizablePanel | ||
| defaultSize={timeline} | ||
| minSize={15} | ||
| maxSize={70} | ||
| onResize={setTimeline} | ||
| className="min-h-0" | ||
| > | ||
| <Timeline /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| <ResizablePanel | ||
| defaultSize={propertiesPanel} | ||
| minSize={15} | ||
| maxSize={40} | ||
| onResize={setPropertiesPanel} | ||
| className="min-w-0" | ||
| > | ||
| <PropertiesPanel /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| ) : activePreset === "vertical-preview" ? ( | ||
| <ResizablePanelGroup | ||
| key={`vertical-preview-${activePreset}-${resetCounter}`} | ||
| direction="horizontal" | ||
| className="h-full w-full gap-[0.18rem] px-3 pb-3" | ||
| > | ||
| <ResizablePanel | ||
| defaultSize={100 - previewPanel} | ||
| minSize={60} | ||
| className="min-w-0 min-h-0" | ||
| > | ||
| <ResizablePanelGroup | ||
| direction="vertical" | ||
| className="h-full w-full gap-[0.18rem]" | ||
| > | ||
| <PropertiesPanel /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| {/* Timeline */} | ||
| <ResizablePanel | ||
| defaultSize={timeline} | ||
| minSize={15} | ||
| maxSize={70} | ||
| onResize={setTimeline} | ||
| className="min-h-0 px-3 pb-3" | ||
| <ResizablePanel | ||
| defaultSize={mainContent} | ||
| minSize={30} | ||
| maxSize={85} | ||
| onResize={setMainContent} | ||
| className="min-h-0" | ||
| > | ||
| <ResizablePanelGroup | ||
| direction="horizontal" | ||
| className="h-full w-full gap-[0.19rem]" | ||
| > | ||
| <ResizablePanel | ||
| defaultSize={toolsPanel} | ||
| minSize={15} | ||
| maxSize={40} | ||
| onResize={setToolsPanel} | ||
| className="min-w-0 rounded-sm" | ||
| > | ||
| <MediaPanel /> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| <ResizablePanel | ||
| defaultSize={propertiesPanel} | ||
| minSize={15} | ||
| maxSize={40} | ||
| onResize={setPropertiesPanel} | ||
| className="min-w-0" | ||
| > | ||
| <PropertiesPanel /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| <ResizablePanel | ||
| defaultSize={timeline} | ||
| minSize={15} | ||
| maxSize={70} | ||
| onResize={setTimeline} | ||
| className="min-h-0" | ||
| > | ||
| <Timeline /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| <ResizablePanel | ||
| defaultSize={previewPanel} | ||
| minSize={30} | ||
| onResize={setPreviewPanel} | ||
| className="min-w-0 min-h-0" | ||
| > | ||
| <PreviewPanel /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| ) : ( | ||
| <ResizablePanelGroup | ||
| key={`default-${activePreset}-${resetCounter}`} | ||
| direction="vertical" | ||
| className="h-full w-full gap-[0.18rem]" | ||
| > | ||
| <Timeline /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| <ResizablePanel | ||
| defaultSize={mainContent} | ||
| minSize={30} | ||
| maxSize={85} | ||
| onResize={setMainContent} | ||
| className="min-h-0" | ||
| > | ||
| {/* Main content area */} | ||
| <ResizablePanelGroup | ||
| direction="horizontal" | ||
| className="h-full w-full gap-[0.19rem] px-3" | ||
| > | ||
| {/* Tools Panel */} | ||
| <ResizablePanel | ||
| defaultSize={toolsPanel} | ||
| minSize={15} | ||
| maxSize={40} | ||
| onResize={setToolsPanel} | ||
| className="min-w-0 rounded-sm" | ||
| > | ||
| <MediaPanel /> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| {/* Preview Area */} | ||
| <ResizablePanel | ||
| defaultSize={previewPanel} | ||
| minSize={30} | ||
| onResize={setPreviewPanel} | ||
| className="min-w-0 min-h-0 flex-1" | ||
| > | ||
| <PreviewPanel /> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| <ResizablePanel | ||
| defaultSize={propertiesPanel} | ||
| minSize={15} | ||
| maxSize={40} | ||
| onResize={setPropertiesPanel} | ||
| className="min-w-0" | ||
| > | ||
| <PropertiesPanel /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| </ResizablePanel> | ||
|
|
||
| <ResizableHandle withHandle /> | ||
|
|
||
| {/* Timeline */} | ||
| <ResizablePanel | ||
| defaultSize={timeline} | ||
| minSize={15} | ||
| maxSize={70} | ||
| onResize={setTimeline} | ||
| className="min-h-0 px-3 pb-3" | ||
| > | ||
| <Timeline /> | ||
| </ResizablePanel> | ||
| </ResizablePanelGroup> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider refactoring to reduce code duplication.
The current implementation has significant code duplication across the four layout configurations. Each layout repeats similar ResizablePanel and ResizablePanelGroup structures with only arrangement differences. This makes the code harder to maintain and increases the risk of inconsistencies.
Consider extracting common panel components or using a configuration-driven approach to reduce duplication.
Would you like me to help refactor this into a more maintainable structure? We could create reusable panel components or use a configuration object to define each layout's structure.
🤖 Prompt for AI Agents
In apps/web/src/app/editor/[project_id]/page.tsx between lines 159 and 452, the
code has repetitive JSX structures for different activePreset layouts with
similar ResizablePanel and ResizablePanelGroup components. To fix this, refactor
by extracting common panel groups and panels into reusable components or create
a configuration-driven rendering approach that defines layout structures and
panel sizes. This will reduce duplication, improve maintainability, and make it
easier to update layouts consistently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
apps/web/src/app/editor/[project_id]/page.tsx (1)
158-452: Code duplication already flagged - focus on correctness verification.The significant code duplication in the layout configurations has already been identified in previous reviews. Beyond the duplication concern, verify that each preset layout is correctly implemented and the panel size calculations are accurate.
#!/bin/bash # Description: Verify that panel size calculations are consistent across all preset layouts # Expected: All layouts should have consistent min/max sizes and proper default size calculations # Extract all defaultSize calculations from the layouts rg -A 1 -B 1 "defaultSize.*-" apps/web/src/app/editor/ # Check for any hardcoded calculations that might be inconsistent rg "100.*-.*Panel|defaultSize.*[0-9]" apps/web/src/app/editor/\[project_id\]/page.tsx # Verify that all presets use the same min/max constraints rg -A 5 -B 5 "minSize|maxSize" apps/web/src/app/editor/\[project_id\]/page.tsx | grep -E "minSize|maxSize" | sort | uniq -c
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/src/app/editor/[project_id]/page.tsx(2 hunks)apps/web/src/stores/panel-store.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
**/*.{js,jsx,ts,tsx}: Don't use consecutive spaces in regular expression literals.
Don't use theargumentsobject.
Don't use the comma operator.
Don't write functions that exceed a given Cognitive Complexity score.
Don't use unnecessary boolean casts.
Don't use unnecessary callbacks with flatMap.
Use for...of statements instead of Array.forEach.
Don't create classes that only have static members (like a static namespace).
Don't use this and super in static contexts.
Don't use unnecessary catch clauses.
Don't use unnecessary constructors.
Don't use unnecessary continue statements.
Don't export empty modules that don't change anything.
Don't use unnecessary escape sequences in regular expression literals.
Don't use unnecessary labels.
Don't use unnecessary nested block statements.
Don't rename imports, exports, and destructured assignments to the same name.
Don't use unnecessary string or template literal concatenation.
Don't use String.raw in template literals when there are no escape sequences.
Don't use useless case statements in switch statements.
Don't use ternary operators when simpler alternatives exist.
Don't use uselessthisaliasing.
Don't initialize variables to undefined.
Don't use the void operators (they're not familiar).
Use arrow functions instead of function expressions.
Use Date.now() to get milliseconds since the Unix Epoch.
Use .flatMap() instead of map().flat() when possible.
Use literal property access instead of computed property access.
Don't use parseInt() or Number.parseInt() when binary, octal, or hexadecimal literals work.
Use concise optional chaining instead of chained logical expressions.
Use regular expression literals instead of the RegExp constructor when possible.
Don't use number literal object member names that aren't base 10 or use underscore separators.
Remove redundant terms from logical expressions.
Use while loops instead of for loops when you don't need initializer and update expressions.
Don't reassign const variables....
Files:
apps/web/src/stores/panel-store.tsapps/web/src/app/editor/[project_id]/page.tsx
**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Don't use primitive type aliases or misleading types.
Don't use empty type parameters in type aliases and interfaces.
Don't use any or unknown as type constraints.
Don't return a value from a function with the return type 'void'.
Don't use the TypeScript directive @ts-ignore.
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.
Don't use TypeScript namespaces.
Don't use non-null assertions with the!postfix operator.
Don't use parameter properties in class constructors.
Don't use user-defined types.
Useas constinstead of literal types and type annotations.
Use eitherT[]orArray<T>consistently.
Initialize each enum member value explicitly.
Useexport typefor types.
Useimport typefor types.
Make sure all enum members are literal values.
Don't use TypeScript const enum.
Don't declare empty interfaces.
Don't let variables evolve into any type through reassignments.
Don't use the any type.
Don't misuse the non-null assertion operator (!) in TypeScript files.
Don't use implicit any type on variable declarations.
Don't merge interfaces and classes unsafely.
Don't use overload signatures that aren't next to each other.
Use the namespace keyword instead of the module keyword to declare TypeScript namespaces.
Use consistent accessibility modifiers on class properties and methods.
Use function types instead of object types with call signatures.
Don't use void type outside of generic or return types.
**/*.{ts,tsx}: 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.
Don't use TypeScript namespaces.
Don't use non-null assertions with the!postfix operator.
Don't use parameter properties in class constructors.
Don't use user-defined types.
Useas constinstead of literal types and...
Files:
apps/web/src/stores/panel-store.tsapps/web/src/app/editor/[project_id]/page.tsx
**/*.{jsx,tsx}
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
**/*.{jsx,tsx}: Don't useaccessKeyattribute on any HTML element.
Don't setaria-hidden="true"on focusable elements.
Don't add ARIA roles, states, and properties to elements that don't support them.
Don't use distracting elements like<marquee>or<blink>.
Only use thescopeprop on<th>elements.
Don't assign non-interactive ARIA roles to interactive HTML elements.
Make sure label elements have text content and are associated with an input.
Don't assign interactive ARIA roles to non-interactive HTML elements.
Don't assigntabIndexto non-interactive HTML elements.
Don't use positive integers fortabIndexproperty.
Don't include "image", "picture", or "photo" in img alt prop.
Don't use explicit role property that's the same as the implicit/default role.
Make static elements with click handlers use a valid role attribute.
Always include atitleelement for SVG elements.
Give all elements requiring alt text meaningful information for screen readers.
Make sure anchors have content that's accessible to screen readers.
AssigntabIndexto non-interactive HTML elements witharia-activedescendant.
Include all required ARIA attributes for elements with ARIA roles.
Make sure ARIA properties are valid for the element's supported roles.
Always include atypeattribute for button elements.
Make elements with interactive roles and handlers focusable.
Give heading elements content that's accessible to screen readers (not hidden witharia-hidden).
Always include alangattribute on the html element.
Always include atitleattribute for iframe elements.
AccompanyonClickwith at least one of:onKeyUp,onKeyDown, oronKeyPress.
AccompanyonMouseOver/onMouseOutwithonFocus/onBlur.
Include caption tracks for audio and video elements.
Use semantic elements instead of role attributes in JSX.
Make sure all anchors are valid and navigable.
Ensure all ARIA properties (aria-*) are valid.
Use valid, non-abstract ARIA roles for elements with...
Files:
apps/web/src/app/editor/[project_id]/page.tsx
🧠 Learnings (4)
📚 Learning: the file apps/web/src/components/editor/media-panel/views/media.tsx uses "use client" directive, mak...
Learnt from: khanguyen74
PR: OpenCut-app/OpenCut#466
File: apps/web/src/components/editor/media-panel/views/media.tsx:47-52
Timestamp: 2025-07-26T21:07:57.582Z
Learning: The file apps/web/src/components/editor/media-panel/views/media.tsx uses "use client" directive, making it client-only code where window object is always available, so SSR safety checks are not needed.
Applied to files:
apps/web/src/app/editor/[project_id]/page.tsx
📚 Learning: applies to **/*.{jsx,tsx} : use `<>...` instead of `...`....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{jsx,tsx} : Use `<>...</>` instead of `<Fragment>...</Fragment>`.
Applied to files:
apps/web/src/app/editor/[project_id]/page.tsx
📚 Learning: applies to **/*.{jsx,tsx} : don't use unnecessary fragments....
Learnt from: CR
PR: OpenCut-app/OpenCut#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-27T22:14:46.402Z
Learning: Applies to **/*.{jsx,tsx} : Don't use unnecessary fragments.
Applied to files:
apps/web/src/app/editor/[project_id]/page.tsx
📚 Learning: user simonorzel26 prefers incremental refactoring approach: moving code first to reduce pr complexit...
Learnt from: simonorzel26
PR: OpenCut-app/OpenCut#324
File: apps/web/src/components/editor/timeline/timeline-content.tsx:9-34
Timestamp: 2025-07-17T08:22:10.492Z
Learning: User simonorzel26 prefers incremental refactoring approach: moving code first to reduce PR complexity, then cleaning up in separate single-responsibility PRs. This strategy prioritizes safety and manageable PR sizes over immediate perfect code structure.
Applied to files:
apps/web/src/app/editor/[project_id]/page.tsx
🔇 Additional comments (9)
apps/web/src/stores/panel-store.ts (7)
4-8: LGTM! Clean type definition for panel presets.The union type clearly defines the available presets and uses kebab-case consistently for multi-word preset names.
10-16: Well-structured interface for panel sizes.The
PanelSizesinterface provides a clean contract for panel size configurations, covering all the necessary panels in the editor.
49-68: LGTM! Well-designed state interface.The interface properly extends
PanelSizesand adds preset-specific state management with clear action definitions.
152-183: LGTM! Well-implemented preset switching logic.The
setActivePresetfunction correctly:
- Saves current sizes to the outgoing preset
- Applies default + custom sizes for the incoming preset
- Updates the active preset atomically
185-204: LGTM! Proper reset implementation.The
resetPresetfunction correctly:
- Clears custom sizes for the target preset
- Increments reset counter to trigger UI remounts
- Only updates current panel sizes if resetting the active preset
206-221: LGTM! Clean getter implementation.The
getCurrentPresetSizesfunction provides a clean way to retrieve current panel sizes.
229-229: LGTM! Proper export of preset configurations.Exporting
PRESET_CONFIGSallows other components to access the default configurations when needed.apps/web/src/app/editor/[project_id]/page.tsx (2)
33-34: LGTM! Proper integration with panel store.The addition of
activePresetandresetCounterfrom the panel store enables dynamic layout switching and proper remounting on resets.
160-160: LGTM! Proper key usage for component remounting.The unique keys combining
activePresetandresetCounterensure proper React component remounting when presets change or are reset, which is essential for the resizable panels to reinitialize with correct sizes.Also applies to: 235-235, 310-310, 385-385
| const PRESET_CONFIGS: Record<PanelPreset, PanelSizes> = { | ||
| default: { | ||
| toolsPanel: 25, | ||
| previewPanel: 50, | ||
| propertiesPanel: 25, | ||
| mainContent: 70, | ||
| timeline: 30, | ||
| }, | ||
| media: { | ||
| toolsPanel: 30, | ||
| previewPanel: 45, | ||
| propertiesPanel: 25, | ||
| mainContent: 100, | ||
| timeline: 25, | ||
| }, | ||
| inspector: { | ||
| toolsPanel: 25, | ||
| previewPanel: 50, | ||
| propertiesPanel: 25, | ||
| mainContent: 100, | ||
| timeline: 25, | ||
| }, | ||
| "vertical-preview": { | ||
| toolsPanel: 25, | ||
| previewPanel: 40, | ||
| propertiesPanel: 35, | ||
| mainContent: 100, | ||
| timeline: 25, | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify preset configurations align with UI requirements.
The preset configurations define different panel arrangements, but ensure these values work well with the actual UI layouts and provide good user experience across different screen sizes.
🏁 Script executed:
#!/bin/bash
# Description: Check if there are any UI tests or documentation that validate these preset configurations
# Expected: Find test files or documentation that verify these values work well in practice
# Search for test files related to panel presets
fd -e test.ts -e test.tsx -e spec.ts -e spec.tsx | xargs rg -l "preset|panel.*size" 2>/dev/null || echo "No test files found"
# Search for documentation about panel configurations
fd README.md DESIGN.md | xargs rg -l -i "panel|preset" 2>/dev/null || echo "No relevant documentation found"
# Look for any configuration validation or constraints
rg -A 5 -B 5 "minSize|maxSize.*panel" apps/web/src/Length of output: 22131
Fix panel presets to respect UI min/max constraints
The PRESET_CONFIGS values must fall within the ResizablePanel minSize/maxSize bounds defined in page.tsx:
- toolsPanel: 15–40
- previewPanel: ≥30 (no max)
- propertiesPanel: 15–40
- mainContent: 30–85
- timeline: 15–70
Currently, three presets exceed the mainContent maxSize of 85:
• apps/web/src/stores/panel-store.ts (lines 18–47)
– media.mainContent = 100
– inspector.mainContent = 100
– vertical-preview.mainContent = 100
Please adjust these to ≤85 (for example 85) and verify all other values adhere to their respective ranges. Consider adding a test or documentation to enforce these constraints.
🤖 Prompt for AI Agents
In apps/web/src/stores/panel-store.ts between lines 18 and 47, the mainContent
values in the media, inspector, and vertical-preview presets exceed the maxSize
limit of 85. Adjust these mainContent values from 100 to 85 to comply with the
ResizablePanel constraints. Also, review all other panel size values to ensure
they fall within their specified min/max ranges: toolsPanel and propertiesPanel
between 15 and 40, previewPanel at least 30, mainContent between 30 and 85, and
timeline between 15 and 70. Optionally, add a test or documentation to enforce
these size constraints going forward.
| setToolsPanel: (size) => { | ||
| const { activePreset, presetCustomSizes } = get(); | ||
| set({ | ||
| toolsPanel: size, | ||
| presetCustomSizes: { | ||
| ...presetCustomSizes, | ||
| [activePreset]: { | ||
| ...presetCustomSizes[activePreset], | ||
| toolsPanel: size, | ||
| }, | ||
| }, | ||
| }); | ||
| }, | ||
| setPreviewPanel: (size) => { | ||
| const { activePreset, presetCustomSizes } = get(); | ||
| set({ | ||
| previewPanel: size, | ||
| presetCustomSizes: { | ||
| ...presetCustomSizes, | ||
| [activePreset]: { | ||
| ...presetCustomSizes[activePreset], | ||
| previewPanel: size, | ||
| }, | ||
| }, | ||
| }); | ||
| }, | ||
| setPropertiesPanel: (size) => { | ||
| const { activePreset, presetCustomSizes } = get(); | ||
| set({ | ||
| propertiesPanel: size, | ||
| presetCustomSizes: { | ||
| ...presetCustomSizes, | ||
| [activePreset]: { | ||
| ...presetCustomSizes[activePreset], | ||
| propertiesPanel: size, | ||
| }, | ||
| }, | ||
| }); | ||
| }, | ||
| setMainContent: (size) => { | ||
| const { activePreset, presetCustomSizes } = get(); | ||
| set({ | ||
| mainContent: size, | ||
| presetCustomSizes: { | ||
| ...presetCustomSizes, | ||
| [activePreset]: { | ||
| ...presetCustomSizes[activePreset], | ||
| mainContent: size, | ||
| }, | ||
| }, | ||
| }); | ||
| }, | ||
| setTimeline: (size) => { | ||
| const { activePreset, presetCustomSizes } = get(); | ||
| set({ | ||
| timeline: size, | ||
| presetCustomSizes: { | ||
| ...presetCustomSizes, | ||
| [activePreset]: { | ||
| ...presetCustomSizes[activePreset], | ||
| timeline: size, | ||
| }, | ||
| }, | ||
| }); | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Reduce code duplication in panel setters.
All five panel setter functions follow identical patterns with only the property name changing. This violates DRY principles and makes maintenance more difficult.
Consider refactoring to a generic setter function:
+ setPanelSize: (panelType: keyof PanelSizes, size: number) => {
+ const { activePreset, presetCustomSizes } = get();
+ set({
+ [panelType]: size,
+ presetCustomSizes: {
+ ...presetCustomSizes,
+ [activePreset]: {
+ ...presetCustomSizes[activePreset],
+ [panelType]: size,
+ },
+ },
+ });
+ },
- setToolsPanel: (size) => {
- const { activePreset, presetCustomSizes } = get();
- set({
- toolsPanel: size,
- presetCustomSizes: {
- ...presetCustomSizes,
- [activePreset]: {
- ...presetCustomSizes[activePreset],
- toolsPanel: size,
- },
- },
- });
- },
+ setToolsPanel: (size) => get().setPanelSize('toolsPanel', size),Apply similar changes to the other four setters.
🤖 Prompt for AI Agents
In apps/web/src/stores/panel-store.ts between lines 85 and 149, the five panel
setter functions are nearly identical except for the property they update,
causing code duplication. Refactor by creating a single generic setter function
that takes the panel name and size as parameters, then updates the corresponding
state and presetCustomSizes dynamically. Replace the existing five setters with
calls to this generic function to adhere to DRY principles and simplify
maintenance.
|
oh wait the ui is beautiful here, let me merge this, one sec! |
|
broke the github tracking with that merge, will fix in a bit |
Description
This PR adds panel presets to the editor, so you can have different panel layouts optimised for specific workflows. The feature includes 4 built-in presets (Default, Media, Inspector, Vertical Preview) with a dropdown selector in the editor header.
Fixes # (issue)
Linter formatted some other files. They did not break anything before.
Type of change
How Has This Been Tested?
Manually tested all 4 panel presets (Default, Media, Inspector, Vertical Preview). Tested panel resizing within each preset and verified persistence across preset switches.
Test Configuration:
Screenshots (if applicable)
Demo.mp4
Checklist:
Additional context
None.
Summary by CodeRabbit
New Features
Improvements
Style
Bug Fixes