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:
@@ -0,0 +1,75 @@
|
||||
import { useState, useEffect, useMemo } from "react";
|
||||
import type { RegistryItem } from "@hyperframes/core/registry";
|
||||
import { type BlockCategory, resolveBlockCategory } from "../utils/blockCategories";
|
||||
|
||||
export type CatalogItem = RegistryItem & {
|
||||
category: BlockCategory;
|
||||
};
|
||||
|
||||
export function useBlockCatalog() {
|
||||
const [blocks, setBlocks] = useState<CatalogItem[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [search, setSearch] = useState("");
|
||||
const [category, setCategory] = useState<BlockCategory | null>(null);
|
||||
|
||||
// fallow-ignore-next-line complexity
|
||||
useEffect(() => {
|
||||
const CATEGORY_ORDER: Record<BlockCategory, number> = {
|
||||
captions: 0,
|
||||
vfx: 1,
|
||||
transitions: 2,
|
||||
effects: 3,
|
||||
social: 4,
|
||||
data: 5,
|
||||
scenes: 6,
|
||||
};
|
||||
|
||||
let cancelled = false;
|
||||
(async () => {
|
||||
try {
|
||||
const res = await fetch("/api/registry/blocks");
|
||||
if (!res.ok) throw new Error("Failed to load catalog");
|
||||
const data = (await res.json()) as RegistryItem[];
|
||||
if (cancelled) return;
|
||||
const items = data
|
||||
.map((b) => ({ ...b, category: resolveBlockCategory(b.tags) }))
|
||||
.sort((a, b) => (CATEGORY_ORDER[a.category] ?? 9) - (CATEGORY_ORDER[b.category] ?? 9));
|
||||
setBlocks(items);
|
||||
} catch (err) {
|
||||
if (cancelled) return;
|
||||
setError(err instanceof Error ? err.message : "Failed to load catalog");
|
||||
} finally {
|
||||
if (!cancelled) setLoading(false);
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const filteredBlocks = useMemo(() => {
|
||||
let result = blocks;
|
||||
if (category) {
|
||||
result = result.filter((b) => b.category === category);
|
||||
}
|
||||
if (search.trim()) {
|
||||
const q = search.toLowerCase();
|
||||
result = result.filter(
|
||||
(b) => b.title.toLowerCase().includes(q) || b.description.toLowerCase().includes(q),
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}, [blocks, category, search]);
|
||||
|
||||
return {
|
||||
blocks,
|
||||
loading,
|
||||
error,
|
||||
search,
|
||||
setSearch,
|
||||
category,
|
||||
setCategory,
|
||||
filteredBlocks,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user