Skip to content

feat: assets cleanup and video player design#156

Merged
WINOFFRG merged 4 commits into
mainfrom
fix/1506
Jun 18, 2026
Merged

feat: assets cleanup and video player design#156
WINOFFRG merged 4 commits into
mainfrom
fix/1506

Conversation

@WINOFFRG

@WINOFFRG WINOFFRG commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Review in cubic

Summary by CodeRabbit

Release Notes

  • New Features
    • Added an asset metadata overlay in the video player showing title/description.
    • Added optional year support for video assets.
    • Enabled configurable player controls auto-hide, with optional cursor hiding when idle.
    • Added thumbnail support for stream assets; stream preset display now uses titles.
  • Improvements
    • Refreshed the playlist dropdown UI and item layout with tooltips, clamped text, a current indicator, and lazy-loaded thumbnails.
  • Bug Fixes
    • Improved expand/collapse state syncing with URL query parameters.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d3e9bd4b-2725-4024-ae58-2fc21f578b39

📥 Commits

Reviewing files that changed from the base of the PR and between e3e2cf1 and 759aff2.

📒 Files selected for processing (3)
  • apps/www/registry/default/blocks/video-player/components/media-player.tsx
  • apps/www/registry/default/blocks/video-player/components/playlist.tsx
  • apps/www/registry/default/ui/root-container.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/www/registry/default/blocks/video-player/components/playlist.tsx
  • apps/www/registry/default/ui/root-container.tsx

📝 Walkthrough

Walkthrough

The PR adds a timer-based controls auto-hide system and optional cursor hiding to RootContainer, introduces an AssetMetadataOverlay component that displays title/description over the player, refactors StreamPreset from name to required title with poster/thumbnail fields (updating all presets), wires controls visibility configuration through VideoPlayerContainer, improves the playlist dropdown with force-idle and collision handling, and fixes a stale-closure bug in BlockPreviewWithToolbar.

Changes

Video Player Controls, Metadata Overlay, and Stream Preset Refactor

Layer / File(s) Summary
StreamPreset interface and preset data refactor
apps/www/lib/stream-presets.ts, apps/www/components/stream-panel/content-catalog.ts, apps/www/components/stream-panel/use-stream-panel-sync.ts
StreamPreset removes name, makes title required, and retains optional poster/thumbnail; all STREAM_PRESETS entries are updated. BlenderOpenFilmImages gains thumbnail, poster derivation switches to prefer thumbnail, and the custom stream preset switches from name to title.
RootContainer controls auto-hide and cursor-hiding
apps/www/registry/default/ui/root-container.tsx
Adds controlsHideDelay and hideCursorOnIdle props, introduces a hideTimerRef-based timer system with hideControls/showControls computing controlsHidden, rewires pointer/focus/blur handlers to use the new callbacks, conditionally applies cursor-none, reorders event handler composition, and adds timer cleanup effects.
AssetMetadataOverlay component and VideoPlayer integration
apps/www/registry/default/blocks/video-player/components/asset-metadata-overlay.tsx, apps/www/registry/default/blocks/video-player/components/media-player.tsx, apps/www/registry/collection/registry-blocks.ts
New AssetMetadataOverlay reads useAsset for title/description and renders a gradient overlay. VideoPlayerAsset gains optional year, VideoPlayerProps gains controlsHideDelay/hideCursorOnIdle forwarded to RootContainer, AssetMetadataOverlay is placed inside the controls overlay container, and the component is registered in the block registry.
useVideoPlayerControlsVisibility hook and container wiring
apps/www/components/players/video-player/player-container.tsx
Adds useVideoPlayerControlsVisibility hook memoizing controlsHideDelay and hideCursorOnIdle from disabled (mobile portrait) and isMobile; result is computed and spread into VideoPlayer. Custom stream label also switches from name to title.
Playlist force-idle, collision, year display, and lazy loading
apps/www/registry/default/blocks/video-player/components/playlist.tsx, apps/www/registry/default/ui/player-layout.tsx
Playlist ties DropdownMenu onOpenChange to setForceIdle with unmount cleanup, adds containerRef as collisionBoundary in DropdownMenuContent, restyled items, lazy image loading, removes hover-preload UI, and adds a current-asset dot and year display with tooltip. PlayerContainer gains @container modifier for responsive layout.
Stream panel title property usage
apps/www/components/stream-panel/panel-popover.tsx, apps/www/components/stream-panel/presets-overlay.tsx
Updates stream panel components to use preset title instead of name for displaying preset labels in the panel popover and presets overlay UI.
BlockPreviewWithToolbar expandedRef fix
apps/www/components/blocks/preview-pane.tsx
Adds expandedRef to avoid stale closures in handleExpandToggle, syncing the ref in both the toggle handler and the useLayoutEffect that reads expanded from searchParams.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant VideoPlayerContainer
    participant VideoPlayer
    participant RootContainer
    participant AssetMetadataOverlay

    User->>VideoPlayerContainer: renders on device
    VideoPlayerContainer->>VideoPlayerContainer: useVideoPlayerControlsVisibility(disabled, isMobile)
    VideoPlayerContainer->>VideoPlayer: spread controlsVisibility {controlsHideDelay, hideCursorOnIdle}
    VideoPlayer->>RootContainer: pass controlsHideDelay, hideCursorOnIdle
    RootContainer->>RootContainer: pointer move → showControls()
    RootContainer->>RootContainer: pointer idle → hideControls(autoHide) → schedules timer
    RootContainer->>RootContainer: timer fires → setIdle(true), controlsHidden=true
    RootContainer->>RootContainer: hideCursorOnIdle=true → apply cursor-none
    RootContainer->>AssetMetadataOverlay: renders inside controls overlay
    AssetMetadataOverlay->>AssetMetadataOverlay: useAsset() → extract title/description → render gradient overlay
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • WINOFFRG/limeplay#149: Modifies the same BlockPreviewWithToolbar component in preview-pane.tsx, introducing the expand/toolbar functionality that this PR's expandedRef stale-closure fix builds upon.
  • WINOFFRG/limeplay#155: Also updates BlockPreviewWithToolbar's handleExpandToggle in preview-pane.tsx, with overlapping changes to state update and query parameter handling.

Poem

🐰 Hop hop, the controls now hide with grace,
A timer ticks, the cursor finds its place.
Titles gleam atop the player's stage,
name fled the preset, title takes the page.
The playlist idles, lazy loads with care —
A rabbit tidied every state with flair! 🎬

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: refactoring stream preset naming (asset cleanup) and enhancing video player UI/controls (design improvements).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/1506

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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/www/registry/default/blocks/video-player/components/playlist.tsx (1)

76-78: 💤 Low value

Double type assertion masks underlying type mismatch.

The as unknown as ComponentProps<...> pattern bypasses TypeScript's type checking. Since DropdownMenuContent already accepts collisionBoundary and collisionPadding props, consider typing dropdownCollisionProps explicitly or investigating why the types don't align:

♻️ Suggested fix
-  const dropdownCollisionProps = {
+  const dropdownCollisionProps: Pick<
+    ComponentProps<typeof DropdownMenuContent>,
+    "collisionBoundary" | "collisionPadding"
+  > = {
     collisionBoundary: containerRef ?? undefined,
     collisionPadding: 12,
   }

Then spread without the cast:

-        {...(dropdownCollisionProps as unknown as ComponentProps<
-          typeof DropdownMenuContent
-        >)}
+        {...dropdownCollisionProps}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/www/registry/default/blocks/video-player/components/playlist.tsx` around
lines 76 - 78, The double type assertion using `as unknown as
ComponentProps<typeof DropdownMenuContent>` bypasses TypeScript type checking
for the `dropdownCollisionProps` object spread into the DropdownMenuContent
component. Instead of using this double cast, explicitly type
`dropdownCollisionProps` to match the props that DropdownMenuContent expects
(such as collisionBoundary and collisionPadding), or ensure its source type
definition aligns with ComponentProps<typeof DropdownMenuContent>. Once the
types are properly aligned, remove the double assertion and spread the object
directly without the cast.
apps/www/registry/default/ui/root-container.tsx (1)

199-206: ⚡ Quick win

Compose consumer handlers before internal handlers in event composition.

Running internalHandler first prevents consumers from influencing internal behavior via event.defaultPrevented, which weakens composability for this shared UI primitive.

Suggested refactor
 function composeEventHandlers<E extends React.SyntheticEvent>(
   consumerHandler: ((event: E) => void) | undefined,
   internalHandler: (event: E) => void
 ) {
   return (event: E) => {
-    internalHandler(event)
     consumerHandler?.(event)
+    if (!event.defaultPrevented) {
+      internalHandler(event)
+    }
   }
 }

As per coding guidelines, “Never block event propagation — compose events.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/www/registry/default/ui/root-container.tsx` around lines 199 - 206, In
the composeEventHandlers function, reverse the order of handler execution so
that consumerHandler is called before internalHandler. This allows consumers to
set event.defaultPrevented and have that influence internal behavior, improving
composability of this shared UI primitive. Change the return statement to call
consumerHandler?.(event) first, followed by internalHandler(event).

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/www/components/stream-panel/content-catalog.ts`:
- Line 45: The BlenderOpenFilmImages interface at line 45 now includes the
thumbnail field, but the BlenderOpenFilmImagesSchema Zod schema definition has
not been updated to match. Add the thumbnail field definition to
BlenderOpenFilmImagesSchema to ensure the schema properly validates and
preserves the thumbnail field when parsing Blender stream payloads, keeping the
schema and interface in sync.

In `@apps/www/lib/stream-presets.ts`:
- Line 42: The refactor in stream-presets.ts replaced the `name` property with a
required `title` property on line 42, but downstream code in
apps/www/components/stream-panel/presets-overlay.tsx still references the old
`preset.name` property, causing type errors and rendering issues. Update all
references to `preset.name` in the presets-overlay.tsx component to use
`preset.title` instead to align with the refactored contract.

In `@apps/www/registry/default/blocks/video-player/components/playlist.tsx`:
- Around line 128-133: The year display in the playlist component lacks
null-safety, causing inconsistency between the title attribute and rendered
content. When asset.year is undefined or null, String(asset.year) produces
"undefined" or "null" in the title attribute while {asset.year} renders nothing.
To fix this, add a null/undefined check and use a consistent fallback value
(such as an empty string or a placeholder) for both the title attribute and the
rendered content in the span element. This ensures the behavior is consistent
whether the year data is present or missing.

In `@apps/www/registry/default/ui/root-container.tsx`:
- Around line 152-157: The onBlur handler in the root-container is hiding
controls on every blur event, including when focus moves between child elements
within the container. To fix this, modify the onBlur handler to only call
hideControls() when focus actually exits the root container entirely. Check the
blur event's relatedTarget property to determine if focus is moving to an
element outside the container, and only hide controls if the relatedTarget is
null or not a descendant of the root container. Keep the showControls() call in
onFocus unchanged.

---

Nitpick comments:
In `@apps/www/registry/default/blocks/video-player/components/playlist.tsx`:
- Around line 76-78: The double type assertion using `as unknown as
ComponentProps<typeof DropdownMenuContent>` bypasses TypeScript type checking
for the `dropdownCollisionProps` object spread into the DropdownMenuContent
component. Instead of using this double cast, explicitly type
`dropdownCollisionProps` to match the props that DropdownMenuContent expects
(such as collisionBoundary and collisionPadding), or ensure its source type
definition aligns with ComponentProps<typeof DropdownMenuContent>. Once the
types are properly aligned, remove the double assertion and spread the object
directly without the cast.

In `@apps/www/registry/default/ui/root-container.tsx`:
- Around line 199-206: In the composeEventHandlers function, reverse the order
of handler execution so that consumerHandler is called before internalHandler.
This allows consumers to set event.defaultPrevented and have that influence
internal behavior, improving composability of this shared UI primitive. Change
the return statement to call consumerHandler?.(event) first, followed by
internalHandler(event).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 787fc539-31bb-4254-bca0-97cadc71a979

📥 Commits

Reviewing files that changed from the base of the PR and between 8047d1c and 0441112.

📒 Files selected for processing (9)
  • apps/www/components/blocks/preview-pane.tsx
  • apps/www/components/players/video-player/player-container.tsx
  • apps/www/components/stream-panel/content-catalog.ts
  • apps/www/components/stream-panel/use-stream-panel-sync.ts
  • apps/www/lib/stream-presets.ts
  • apps/www/registry/default/blocks/video-player/components/asset-metadata-overlay.tsx
  • apps/www/registry/default/blocks/video-player/components/media-player.tsx
  • apps/www/registry/default/blocks/video-player/components/playlist.tsx
  • apps/www/registry/default/ui/root-container.tsx

Comment thread apps/www/components/stream-panel/content-catalog.ts
Comment thread apps/www/lib/stream-presets.ts
Comment thread apps/www/registry/default/ui/root-container.tsx Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 9 files

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread apps/www/components/stream-panel/content-catalog.ts
Comment thread apps/www/registry/default/ui/root-container.tsx
Comment thread apps/www/registry/default/blocks/video-player/components/playlist.tsx Outdated
@WINOFFRG WINOFFRG merged commit 0e455ca into main Jun 18, 2026
7 checks passed
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.

1 participant