@livo-tv/blocks
v1.37.0
Published
Shared UI components for Livo applications
Maintainers
Readme
@livo-tv/blocks
Shared UI components for Livo applications.
The main entry is a Client Component boundary ("use client"). Import avatar helpers from @livo-tv/blocks/avatar in React Server Components. Import VideoPlayer, curtains, shaders, and playback beacons from @livo-tv/blocks/video so apps that only need chrome (auth, home, docs) never resolve optional HLS / shader peers.
Install
pnpm add @livo-tv/blocksOptional peers:
hls.js—@livo-tv/blocks/video(VideoPlayer/useHlsPlayback)@shadergradient/react(plusthree/@react-three/fiber/three-stdlib/camera-controls) —@livo-tv/blocks/video(ShaderCurtain)framer-motion—AvatarEditorDialog,ThemeSwitcher,LanguageSwitchernext-themes—ThemeSwitcher
Tailwind
Scan the built package so utilities are not purged:
@source "../../node_modules/@livo-tv/blocks/dist/*.{js,cjs,mjs}";Consumers must define the same shadcn CSS variables (--primary, --background, --muted, …) that Livo frontends already ship.
Video
import { VideoPlayer } from "@livo-tv/blocks/video";
<VideoPlayer
src={playbackUrl}
mode={status === "ended" ? "vod" : "live"}
labels={labels}
onError={reportPlaybackError}
/>;The package is reporting-agnostic. Wire onError / onFirstPlay in the app.
Curtains
CurtainPicker is presentational. Apps load the catalog, upload, and confirm deletes; the block only renders tiles and calls back.
import { CurtainPicker, CurtainPickerSkeleton } from "@livo-tv/blocks/video";
<CurtainPicker
curtains={curtains}
value={curtainId}
onChange={setCurtainId}
allowNone
groupByOwner
variant="compact"
onMakeDefault={setDefault}
onDelete={requestDelete}
canDelete={(curtain) => curtain.ownerType === "organization"}
labels={t.raw("curtains.picker")}
/>;Image tiles use the asset URL. Video tiles show a muted looping preview only while the card is on screen, and freeze on prefers-reduced-motion. variant="compact" is a selected preview plus a dense thumbnail grid (thumbs stay frozen). Pass isDefault on each item (org setting or platform flag). Use CurtainPickerSkeleton for a layout-matched loading state.
Avatar
import { AvatarEditorDialog } from "@livo-tv/blocks";
<AvatarEditorDialog
value={preview}
onChange={setPreview}
onSave={async (dataUrl) => {
const uploaded = await uploadAvatar(dataUrl);
return uploaded.success;
}}
placeholder={t("select")}
editLabel={t("edit")}
dialogTitle={t("dialogTitle")}
/>;i18n
Defaults are English. Pass labels (and AvatarEditor labels) from next-intl. LanguageSwitcher defaults to en / es / pt.
