mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-10 22:20:14 +00:00
feat(studio): full Blocks panel — browse, search, add, drag-and-drop registry items
Adds a Blocks tab to the Studio left sidebar with the full 78-item registry
catalog (58 blocks + 20 components). Users can browse by category, search by
title/description, preview CDN-hosted poster thumbnails with video-on-hover,
and install items on-demand with one click or drag-to-timeline.
Core changes:
- BlockCategory type + resolveBlockCategory() for 7 categories (Captions, VFX,
Transitions, Effects, Social, Data, Scenes)
- Registry API routes: GET /api/registry/blocks (catalog) + POST install
- StudioApiAdapter extended with listRegistryCatalog + installRegistryBlock
- Vite adapter reads from disk; CLI adapter fetches from GitHub (24h cache)
- BlockParam interface + params on 6 blocks for future parameter controls
Studio UI:
- 4th sidebar tab "Blocks" with responsive grid, category pills, search bar
- BlockCard: CDN poster thumbnail, video autoplay on hover, duration + WebGL badges
- On-demand install: blocks append as sub-compositions on timeline; components
overlay at start=0 spanning full duration with transparent background patching
- TIMELINE_BLOCK_MIME drag-and-drop to timeline
- BlockParamsPanel (Phase 3 scaffold) auto-opens for parameterized blocks
Registry manifests:
- All 58 blocks backfilled with preview: { video, poster } CDN URLs
- All 20 components normalized to object format + poster URLs added
- 6 blocks annotated with params (Liquid Glass/Background, Portal, Chart,
Logo Outro, Magnetic)
- flowchart-vertical preview generated and uploaded to CDN
This commit is contained in:
@@ -8,9 +8,11 @@ import {
|
||||
} from "react";
|
||||
import { CompositionsTab } from "./CompositionsTab";
|
||||
import { AssetsTab } from "./AssetsTab";
|
||||
import { BlocksTab } from "./BlocksTab";
|
||||
import { FileTree } from "../editor/FileTree";
|
||||
import { STUDIO_BLOCKS_PANEL_ENABLED } from "../editor/manualEditingAvailability";
|
||||
|
||||
export type SidebarTab = "compositions" | "assets" | "code";
|
||||
export type SidebarTab = "compositions" | "assets" | "code" | "blocks";
|
||||
|
||||
export interface LeftSidebarHandle {
|
||||
selectTab: (tab: SidebarTab) => void;
|
||||
@@ -22,6 +24,7 @@ function getPersistedTab(): SidebarTab {
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
if (stored === "assets") return "assets";
|
||||
if (stored === "code") return "code";
|
||||
if (stored === "blocks") return "blocks";
|
||||
return "compositions";
|
||||
}
|
||||
|
||||
@@ -48,6 +51,7 @@ interface LeftSidebarProps {
|
||||
onLint?: () => void;
|
||||
linting?: boolean;
|
||||
onToggleCollapse?: () => void;
|
||||
onAddBlock?: (blockName: string) => void;
|
||||
takeoverContent?: ReactNode;
|
||||
}
|
||||
|
||||
@@ -76,6 +80,7 @@ export const LeftSidebar = memo(
|
||||
onLint,
|
||||
linting,
|
||||
onToggleCollapse,
|
||||
onAddBlock,
|
||||
takeoverContent,
|
||||
},
|
||||
ref,
|
||||
@@ -103,7 +108,11 @@ export const LeftSidebar = memo(
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="grid min-w-0 flex-1 gap-0.5 rounded-[18px] bg-neutral-900 p-1 shadow-[inset_0_1px_0_rgba(255,255,255,0.03)]"
|
||||
style={{ gridTemplateColumns: "1fr 1fr 1fr" }}
|
||||
style={{
|
||||
gridTemplateColumns: STUDIO_BLOCKS_PANEL_ENABLED
|
||||
? "1fr 1fr 1fr 1fr"
|
||||
: "1fr 1fr 1fr",
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
@@ -138,6 +147,19 @@ export const LeftSidebar = memo(
|
||||
>
|
||||
Assets
|
||||
</button>
|
||||
{STUDIO_BLOCKS_PANEL_ENABLED && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => selectTab("blocks")}
|
||||
className={`rounded-[14px] px-1.5 py-2 text-[10px] font-semibold truncate transition-all ${
|
||||
tab === "blocks"
|
||||
? "bg-neutral-800 text-white"
|
||||
: "text-neutral-500 hover:text-neutral-200"
|
||||
}`}
|
||||
>
|
||||
Blocks
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{onToggleCollapse && (
|
||||
<button
|
||||
@@ -214,6 +236,10 @@ export const LeftSidebar = memo(
|
||||
</div>
|
||||
)}
|
||||
|
||||
{STUDIO_BLOCKS_PANEL_ENABLED && tab === "blocks" && onAddBlock && (
|
||||
<BlocksTab onAddBlock={onAddBlock} />
|
||||
)}
|
||||
|
||||
{/* Lint button pinned at the bottom */}
|
||||
{onLint && (
|
||||
<div className="border-t border-neutral-800 p-2 flex-shrink-0">
|
||||
|
||||
Reference in New Issue
Block a user