Skip to content

feature: Scroll + Zoom indicators on the Timeline#409

Open
mannix-lei wants to merge 5 commits intoOpenCut-app:mainfrom
mannix-lei:main
Open

feature: Scroll + Zoom indicators on the Timeline#409
mannix-lei wants to merge 5 commits intoOpenCut-app:mainfrom
mannix-lei:main

Conversation

@mannix-lei
Copy link

@mannix-lei mannix-lei commented Jul 22, 2025

Description

Closes #418

fixed the inconsistent MIN_ZOOM value across all timeline zoom components.
add new zoom-related constants

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Test A
  • Test B

Test Configuration:

  • Node version: 18.20.5
  • Browser (if applicable): chrome 138.0.7204.158 (arm64)
  • Operating System: macOs 15.5

Screenshots (if applicable)

2025-07-23.20.26.34.mov

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have added screenshots if ui has been changed
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Additional context

Add any other context about the pull request here.

Summary by CodeRabbit

  • New Features

    • Introduced advanced zoom controls for the timeline, including zoom in/out buttons, a slider for fine adjustments, and a "fit to window" option that automatically adjusts the timeline to fit the visible area.
    • Added keyboard shortcuts for zoom actions and fit-to-window functionality.
  • Improvements

    • Enhanced accessibility of the timeline with improved keyboard navigation and screen reader support.
    • Refined export button layout and icon size for a cleaner appearance.
    • Improved scroll handling and robustness within the timeline view.

@netlify
Copy link

netlify bot commented Jul 22, 2025

👷 Deploy request for appcut pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit b30d5b1

@vercel
Copy link

vercel bot commented Jul 22, 2025

Someone is attempting to deploy a commit to the OpenCut OSS Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 22, 2025

Walkthrough

This update introduces new zoom controls and a "fit to window" feature to the timeline component, refactors scroll handling for improved robustness, and enhances accessibility with additional attributes. New constants and hooks are added for managing zoom logic, and UI elements are updated to support these features and improve usability.

Changes

File(s) Change Summary
apps/web/src/components/editor/timeline-zoom-control.tsx Added new TimelineZoomControl React component for timeline zoom UI, supporting zoom in/out, slider, reset, and fit-to-window.
apps/web/src/constants/timeline-constants.ts Added and exported new zoom constants (MIN_ZOOM, MAX_ZOOM, ZOOM_STEP, WHEEL_ZOOM_STEP), updated ZOOM_LEVELS range, and provided individual exports.
apps/web/src/hooks/use-timeline-zoom-actions.ts Introduced useTimelineZoomActions hook to handle zoom-related actions (zoom in/out, reset, fit-to-window) with action handlers.
apps/web/src/hooks/use-timeline-zoom.ts Refactored to use new zoom constants, added optional onFitToWindow callback, improved wheel and keyboard zoom handling, added keyboard shortcuts for zoom and fit-to-window.
apps/web/src/components/editor-header.tsx Adjusted export button styling and icon size; no functional changes.
apps/web/src/components/editor/timeline/index.tsx Refactored scroll container logic, improved accessibility with new attributes, updated ruler height, replaced old zoom controls with TimelineZoomControl, added "fit to window" zoom calculation and feature, and updated ScrollArea usage.
apps/web/src/constants/actions.ts Extended Action type union with new timeline zoom actions: "zoom-in", "zoom-out", "zoom-reset", and "zoom-fit".
apps/web/src/hooks/use-keyboard-shortcuts-help.ts Added new keyboard shortcut action descriptions for timeline zoom controls under the "View" category.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant TimelineZoomControl
    participant TimelineToolbar
    participant Timeline
    participant useTimelineZoom
    participant useTimelineZoomActions

    User->>TimelineZoomControl: Clicks zoom in/out/reset/fit
    TimelineZoomControl->>TimelineToolbar: Calls onZoomChange / onFitToWindow
    TimelineToolbar->>Timeline: Updates zoomLevel or fits timeline
    Timeline->>useTimelineZoom: Handles zoom logic (wheel/keyboard)
    useTimelineZoom->>useTimelineZoomActions: Registers action handlers
    User->>Timeline: Uses keyboard shortcuts (Ctrl + = / - / 0 / 9)
    Timeline->>useTimelineZoom: Keyboard event processed
Loading

Estimated code review effort

3 (~45 minutes)

Possibly related PRs

Suggested reviewers

  • shreyashguptas

Poem

A timeline stretches, wide and long,
Now zooming in, where details throng.
With buttons bright and sliders neat,
And fit-to-window—oh, what a treat!
Scroll and zoom, with ease anew,
This rabbit cheers the work you do!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 633e7f8 and b30d5b1.

📒 Files selected for processing (3)
  • apps/web/src/components/editor/timeline/index.tsx (12 hunks)
  • apps/web/src/constants/actions.ts (1 hunks)
  • apps/web/src/hooks/use-keyboard-shortcuts-help.ts (1 hunks)
🧠 Learnings (2)
📓 Common learnings
Learnt from: simonorzel26
PR: OpenCut-app/OpenCut#324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.961Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded `ml-48` class in addition to the calculated `leftPosition` for proper alignment. This is intentional and needed for the new timeline layout.
apps/web/src/constants/actions.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.961Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

✅ Files skipped from review due to trivial changes (1)
  • apps/web/src/hooks/use-keyboard-shortcuts-help.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/src/components/editor/timeline/index.tsx
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: simonorzel26
PR: OpenCut-app/OpenCut#324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.961Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded `ml-48` class in addition to the calculated `leftPosition` for proper alignment. This is intentional and needed for the new timeline layout.
apps/web/src/constants/actions.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.961Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build (windows-latest)
🔇 Additional comments (1)
apps/web/src/constants/actions.ts (1)

48-52: LGTM! Clean addition of zoom actions.

The new zoom-related actions are well-implemented with consistent naming, clear comments, and proper TypeScript union syntax. The changes maintain the existing code style and integrate seamlessly with the action system.

✨ Finishing Touches
  • 📝 Generate Docstrings

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (4)
apps/web/src/stores/keybindings-store.ts (1)

28-31: Consider the keybinding choice for zoom-fit.

The zoom keybindings are mostly standard (ctrl+= for zoom-in, ctrl+- for zoom-out, ctrl+0 for zoom-reset), but ctrl+9 for zoom-fit might be unconventional. Many applications use ctrl+0 for fit-to-window, though you've used it for zoom-reset which is also common.

Consider if users might expect a different key for zoom-fit functionality.

apps/web/src/components/editor/timeline-zoom-control.tsx (1)

1-1: Remove unused import

The useState import is not used in this component.

-import { useState } from "react";
apps/web/src/components/editor/timeline-fixed.tsx (1)

62-986: Consider splitting this large component for better maintainability

This component is over 1000 lines long, making it difficult to maintain and test. Consider extracting logical sections into separate components.

Suggested refactoring approach:

  1. Extract the toolbar (lines 585-742) into a TimelineToolbar component
  2. Extract the drag-and-drop logic into a custom hook useTimelineDragDrop
  3. Extract the context menu handlers into a useTimelineContextMenu hook
  4. Extract the time formatting logic into utility functions

This would improve:

  • Code maintainability and readability
  • Testing capabilities
  • Component reusability
  • Developer experience
apps/web/src/components/editor/timeline.tsx (1)

587-614: Consider extracting getScrollableViewport as a utility function.

The helper function is well-implemented but could be extracted to a separate utility file for reusability across other components that need similar scroll container detection.

Consider moving this to a utilities file:

// In utils/scroll.ts
export function getScrollableViewport(containerRef: React.RefObject<HTMLDivElement>): HTMLElement | null {
  if (!containerRef.current) return null;
  
  // First try to find Radix ScrollArea viewport
  const radixViewport = containerRef.current.querySelector("[data-radix-scroll-area-viewport]") as HTMLElement;
  if (radixViewport) return radixViewport;
  
  // Fallback to the container itself if it's scrollable
  const container = containerRef.current;
  const hasOverflow = container && (
    container.style.overflow === 'auto' ||
    container.style.overflow === 'scroll' ||
    // ... rest of the checks
  );
  
  return hasOverflow ? container : null;
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f2a403b and a83ccc4.

📒 Files selected for processing (12)
  • apps/web/src/components/editor/timeline-clean.tsx (1 hunks)
  • apps/web/src/components/editor/timeline-fixed.tsx (1 hunks)
  • apps/web/src/components/editor/timeline-zoom-control.tsx (1 hunks)
  • apps/web/src/components/editor/timeline.tsx (12 hunks)
  • apps/web/src/constants/actions.ts (1 hunks)
  • apps/web/src/constants/timeline-constants.ts (1 hunks)
  • apps/web/src/hooks/use-keyboard-shortcuts-help.ts (1 hunks)
  • apps/web/src/hooks/use-timeline-zoom-actions.ts (1 hunks)
  • apps/web/src/hooks/use-timeline-zoom.ts (2 hunks)
  • apps/web/src/stores/keybindings-store.ts (1 hunks)
  • apps/web/src/stores/timeline-store.ts (2 hunks)
  • apps/web/src/types/keybinding.ts (1 hunks)
🧠 Learnings (10)
📓 Common learnings
Learnt from: simonorzel26
PR: OpenCut-app/OpenCut#324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded `ml-48` class in addition to the calculated `leftPosition` for proper alignment. This is intentional and needed for the new timeline layout.
apps/web/src/constants/actions.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/hooks/use-timeline-zoom-actions.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/constants/timeline-constants.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/stores/timeline-store.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/components/editor/timeline-zoom-control.tsx (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/hooks/use-timeline-zoom.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/components/editor/timeline-fixed.tsx (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/components/editor/timeline.tsx (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/components/editor/timeline-clean.tsx (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

🧬 Code Graph Analysis (1)
apps/web/src/components/editor/timeline.tsx (5)
apps/web/src/hooks/use-timeline-zoom.ts (1)
  • useTimelineZoom (18-115)
apps/web/src/hooks/use-timeline-zoom-actions.ts (1)
  • useTimelineZoomActions (12-38)
apps/web/src/components/editor/timeline-zoom-control.tsx (1)
  • TimelineZoomControl (19-127)
apps/web/src/components/ui/scroll-area.tsx (1)
  • ScrollArea (48-48)
apps/web/src/components/editor/selection-box.tsx (1)
  • SelectionBox (12-58)
🪛 GitHub Actions: Bun CI
apps/web/src/components/editor/timeline-fixed.tsx

[error] 263-263: Type error: Block-scoped variable 'handleDragOver' used before its declaration.

🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: simonorzel26
PR: OpenCut-app/OpenCut#324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded `ml-48` class in addition to the calculated `leftPosition` for proper alignment. This is intentional and needed for the new timeline layout.
apps/web/src/constants/actions.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/hooks/use-timeline-zoom-actions.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/constants/timeline-constants.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/stores/timeline-store.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/components/editor/timeline-zoom-control.tsx (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/hooks/use-timeline-zoom.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/components/editor/timeline-fixed.tsx (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/components/editor/timeline.tsx (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/components/editor/timeline-clean.tsx (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.929Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

🧬 Code Graph Analysis (1)
apps/web/src/components/editor/timeline.tsx (5)
apps/web/src/hooks/use-timeline-zoom.ts (1)
  • useTimelineZoom (18-115)
apps/web/src/hooks/use-timeline-zoom-actions.ts (1)
  • useTimelineZoomActions (12-38)
apps/web/src/components/editor/timeline-zoom-control.tsx (1)
  • TimelineZoomControl (19-127)
apps/web/src/components/ui/scroll-area.tsx (1)
  • ScrollArea (48-48)
apps/web/src/components/editor/selection-box.tsx (1)
  • SelectionBox (12-58)
🪛 GitHub Actions: Bun CI
apps/web/src/components/editor/timeline-fixed.tsx

[error] 263-263: Type error: Block-scoped variable 'handleDragOver' used before its declaration.

🔇 Additional comments (13)
apps/web/src/constants/timeline-constants.ts (2)

78-81: LGTM! The zoom level constants address the PR objective effectively.

The updated MIN_ZOOM value from 0.25 to 0.3 and the addition of MAX_ZOOM at 5 provide consistent boundaries. The ZOOM_LEVELS array progression is logical and covers a good range of zoom options for timeline editing.


83-85: Good practice: Individual constant exports improve modularity.

Exporting MIN_ZOOM, MAX_ZOOM, and ZOOM_LEVELS individually makes them easier to import in other modules without importing the entire TIMELINE_CONSTANTS object.

apps/web/src/types/keybinding.ts (1)

23-23: LGTM! Key additions support zoom functionality.

Adding "+", "-", and "=" to the Key type union is necessary to support the new zoom keyboard shortcuts (ctrl+=, ctrl+-, ctrl+0).

apps/web/src/hooks/use-keyboard-shortcuts-help.ts (1)

63-66: LGTM! Clear and consistent action descriptions.

The zoom action descriptions are well-written and properly categorized under "View". The descriptions follow the existing pattern and will provide clear guidance to users in the help system.

apps/web/src/constants/actions.ts (1)

47-50: LGTM! Well-defined zoom actions.

The four new zoom actions (zoom-in, zoom-out, zoom-reset, zoom-fit) are clearly named, properly documented, and follow the existing action naming conventions. They integrate well with the keybindings and help system changes.

apps/web/src/stores/timeline-store.ts (1)

1162-1179: Well-implemented zoom calculation methods!

The new methods properly use TIMELINE_CONSTANTS including MIN_ZOOM and MAX_ZOOM, ensuring consistency across the application. The calculateFitToWindowZoom method includes thoughtful edge case handling for zero duration.

apps/web/src/components/editor/timeline.tsx (5)

59-60: LGTM! Zoom control imports added correctly.

The new imports for TimelineZoomControl and useTimelineZoomActions are properly structured and follow the project's import conventions.


109-117: Well-implemented fit-to-window functionality.

The handleFitToWindow callback correctly calculates the optimal zoom level based on container width and properly uses useCallback with the correct dependency.


158-163: Zoom actions properly integrated.

The useTimelineZoomActions hook is correctly configured with all necessary props to enable keyboard shortcuts and action-based zoom controls.


878-886: Zoom control UI properly integrated into toolbar.

The TimelineZoomControl component is correctly positioned in the toolbar with appropriate visual separation and all required props.


1-1157: MIN_ZOOM Consistency Verified

All timeline zoom components import and reference the shared MIN_ZOOM constant from timeline-constants.ts. No hard-coded “0.3” values remain.

• apps/web/src/hooks/use-timeline-zoom.ts
• apps/web/src/hooks/use-timeline-zoom-actions.ts
• apps/web/src/components/editor/timeline-zoom-control.tsx

No further changes needed.

apps/web/src/components/editor/timeline-clean.tsx (2)

1-60: Imports properly structured for the new timeline component.

The imports are well-organized and include all necessary dependencies for timeline functionality, zoom controls, and native scroll handling.


195-203: Improved mouse tracking implementation.

Using Date.now() instead of e.timeStamp provides more consistent timing across different browsers. Good improvement over the original implementation.

@mannix-lei mannix-lei changed the title feature: fixed the inconsistent MIN_ZOOM value across all timeline zoom components. feature: Made some optimizations Jul 22, 2025
@mannix-lei mannix-lei changed the title feature: Made some optimizations feature: Made some optimizations within timeline based PR #388 Jul 22, 2025
@mannix-lei mannix-lei changed the title feature: Made some optimizations within timeline based PR #388 feature: Scroll + Zoom indicators on the Timeline Jul 23, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
apps/web/src/hooks/use-timeline-zoom.ts (2)

17-18: Consider implementing zoom persistence or removing unused constant

The ZOOM_STORAGE_KEY constant is defined but not used. If zoom persistence is planned, consider implementing it now. Otherwise, remove this unused constant to keep the code clean.

If you want to implement zoom persistence:

-export function useTimelineZoom({
+export function useTimelineZoom({
   containerRef,
   isInTimeline = false,
   onFitToWindow
 }: UseTimelineZoomProps): UseTimelineZoomReturn {
-  const [zoomLevel, setZoomLevel] = useState(1);
+  const [zoomLevel, setZoomLevel] = useState(() => {
+    const savedZoom = localStorage.getItem(ZOOM_STORAGE_KEY);
+    return savedZoom ? parseFloat(savedZoom) : 1;
+  });
+
+  // Persist zoom level changes
+  useEffect(() => {
+    localStorage.setItem(ZOOM_STORAGE_KEY, zoomLevel.toString());
+  }, [zoomLevel]);

57-62: Consider using a more standard shortcut for fit-to-window

The implementation is solid, but using '9' for fit-to-window is unconventional. Consider:

  1. Using a more standard shortcut like Ctrl/Cmd+Shift+0 or Ctrl/Cmd+Shift+F
  2. Adding a comment explaining why '9' was chosen
  3. Ensuring this shortcut is documented in the UI (tooltip/help)
-          case '9':
+          case '0':
+            if (e.shiftKey) {
+              // Ctrl/Cmd+Shift+0 for fit to window
+              e.preventDefault();
+              if (onFitToWindow) {
+                onFitToWindow();
+              }
+            } else {
+              // Ctrl/Cmd+0 for reset zoom
+              e.preventDefault();
+              setZoomLevel(1);
+            }
+            break;
-            e.preventDefault();
-            if (onFitToWindow) {
-              onFitToWindow();
-            }
-            break;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d056f7 and 633e7f8.

📒 Files selected for processing (5)
  • apps/web/src/components/editor-header.tsx (1 hunks)
  • apps/web/src/components/editor/timeline-zoom-control.tsx (1 hunks)
  • apps/web/src/components/editor/timeline/index.tsx (12 hunks)
  • apps/web/src/constants/timeline-constants.ts (1 hunks)
  • apps/web/src/hooks/use-timeline-zoom.ts (2 hunks)
🧠 Learnings (3)
📓 Common learnings
Learnt from: simonorzel26
PR: OpenCut-app/OpenCut#324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.961Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded `ml-48` class in addition to the calculated `leftPosition` for proper alignment. This is intentional and needed for the new timeline layout.
apps/web/src/components/editor/timeline/index.tsx (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.961Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/hooks/use-timeline-zoom.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.961Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

✅ Files skipped from review due to trivial changes (1)
  • apps/web/src/components/editor-header.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/components/editor/timeline-zoom-control.tsx
  • apps/web/src/constants/timeline-constants.ts
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: simonorzel26
PR: OpenCut-app/OpenCut#324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.961Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded `ml-48` class in addition to the calculated `leftPosition` for proper alignment. This is intentional and needed for the new timeline layout.
apps/web/src/components/editor/timeline/index.tsx (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.961Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

apps/web/src/hooks/use-timeline-zoom.ts (1)

Learnt from: simonorzel26
PR: #324
File: apps/web/src/components/editor/snap-indicator.tsx:43-43
Timestamp: 2025-07-17T08:26:10.961Z
Learning: In the timeline refactor PR #324, the snap indicator component in apps/web/src/components/editor/snap-indicator.tsx requires the hard-coded ml-48 class in addition to the calculated leftPosition for proper alignment. This is intentional and needed for the new timeline layout.

🔇 Additional comments (2)
apps/web/src/hooks/use-timeline-zoom.ts (1)

30-31: Good use of zoom constants!

The wheel zoom handler now properly uses the imported WHEEL_ZOOM_STEP, MIN_ZOOM, and MAX_ZOOM constants, making the zoom behavior consistent and maintainable.

apps/web/src/components/editor/timeline/index.tsx (1)

583-587: Excellent accessibility improvements!

Adding ARIA attributes and tabIndex to the timeline ruler improves keyboard navigation and screen reader support. The increased height (4px → 6px) also enhances visual clarity and click target size.

@mannix-lei
Copy link
Author

#388

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Scroll + Zoom indicators on the Timeline

1 participant