Skip to content
ilinxa/pro-ui

Media Library

alphav0.2.0

Drive-style media library — folders and files, lazy loading, drag-drop upload, drag-to-move, context menus, and multi-type preview.

Category: MediaUpdated: 2026-08-11Created: 2026-06-09Author: ilinxa

Context

A composition-first CMS/asset surface. It owns the Drive shell — storage-quota bar, type-filter chips, folder-card row, thumbnail grid, upload pipeline, and a preview dispatcher — and delegates every actual file render to the shipped viewers (pdf-viewer, code-block, markdown-editor, video-player) plus a folder-navigation file-tree. Ships shadcn-style: one batteries-included <MediaLibrary> plus a headless <MediaLibraryRoot> + à-la-carte parts, so consumers drop what they don't need and tree-shake the unused viewers away.

Installation

Initialize shadcn (once per project)Seeds lib/utils.ts and components.json. Skip if you've already used any shadcn component.
pnpm dlx shadcn@latest init
Register the @ilinxa namespace (once per project)Add to your components.json. Merge with existing config.
"registries": {
  "@ilinxa": "https://ui.ilinxa.com/r/{name}.json"
}
Install the component
pnpm dlx shadcn@latest add @ilinxa/media-library

Add -fixtures for dummy data:

pnpm dlx shadcn@latest add @ilinxa/media-library-fixtures

Preview

11.9 GB of 46.6 GB used26%

Media library

Folders

Brand & logos

2 items · Mar 24

Documents

2 items · Jun 6

Photos

3 items · Jun 9

Video

1 item · Jun 1

Files

PNG512 × 512
PNG

favicon.png

JPG2400 × 1350
JPG

hero-home.jpg

PNG1200 × 630
PNG

og-card.png

Drag-drop files to upload, drag a card onto a folder to move, right-click for actions, double-click a file to preview.

Demo source

demo.tsxtsx

Usage

When to use

Reach for MediaLibrary when you need a Google-Drive-style asset manager — folders + files, lazy loading, drag-drop upload, drag-to-move, right-click menus, and rich multi-type preview. It composes the shipped viewers (pdf-viewer, code-block, markdown-editor, video-player) and a folder file-tree — you supply the data + the backend callbacks.

Full (batteries-included)

import { MediaLibrary } from "@/components/media-library"

export function Example() {
  return (
    <MediaLibrary
      nodes={tree}
      storage={{ used: 12.8e9, total: 50e9 }}
      onLoadChildren={(folderId) => fetchFolder(folderId)}
      onUpload={(files, folderId, progress) => uploadToCdn(files, folderId, progress)}
      onMove={(ids, target) => moveAssets(ids, target)}
      onRename={(id, name) => renameAsset(id, name)}
      onDelete={(ids) => deleteAssets(ids)}
      onCreateFolder={(parentId, name) => createFolder(parentId, name)}
    />
  )
}

Lighter (drop the parts you don't need)

Like shadcn's sidebar, every part is an export. Compose <MediaLibraryRoot> with only the pieces you want — omitting <MediaLibraryLightbox /> / <MediaLibraryDetailsPane /> also tree-shakes the heavy viewers (pdf.js / CodeMirror / marked) out of your bundle.

import {
  MediaLibraryRoot,
  MediaLibraryBreadcrumbs,
  MediaLibraryFolderRow,
  MediaLibraryFileGrid,
} from "@/components/media-library"

<MediaLibraryRoot nodes={tree} onMove={moveAssets} preview={false}>
  <MediaLibraryBreadcrumbs />
  <MediaLibraryFolderRow />
  <MediaLibraryFileGrid />
</MediaLibraryRoot>

Just the preview

import { FilePreview } from "@/components/media-library"

// Anywhere — no library shell. Routes by MIME/extension to the right viewer.
<FilePreview node={{ id: "1", name: "readme.md", type: "file",
  mimeType: "text/markdown", url: "/files/readme.md" }} />

Notes

  • Data: nodes are MediaNode (a superset of the shared FsNode) — give files a url + mimeType for preview, and width/height for the dimension badge.
  • Text preview(code / JSON / txt / Markdown) is fetched from the node's url; pass resolveTextContent for auth / signed URLs.
  • Capabilities are opt-in: omit onUpload / onMove / onDelete / onRename / onCreateFolder and the matching buttons, menu items, and dnd disappear (read-only gallery).
  • Uploads call onUploadonce per file; report that file's percent via the progress callback and resolve with the real MediaNode[].
  • Cut → paste-into-folder moves items; copy/duplicate is deferred to v0.2.

Features

  • Three tiers: full <MediaLibrary>, headless <MediaLibraryRoot> + parts, and standalone primitives (FilePreview, QuotaBar, FileCard)
  • Multi-type preview dispatcher (image / video / pdf / code / json / text / markdown) in both a side pane and a full-screen lightbox with prev/next
  • Lazy-loaded viewers (React.lazy) — dropping the preview parts drops pdf.js / CodeMirror / marked from the bundle
  • Drag-drop upload (optimistic items + per-file progress + retry) via a consumer onUpload callback
  • Drag-to-move files/folders with self/cycle drop validation; right-click context menus; cut → paste move
  • Storage-quota bar, type-filter chips with live counts, breadcrumb navigation, lazy onLoadChildren
  • Controlled/uncontrolled selection + current folder; imperative handle; full label i18n
  • v0.1.2 — F-cross-13 path-b sweep: item context-menu trigger drops `asChild` (`className="contents"` wrapper; right-click bubbles from the card in both backends). Zero public-API change.

Tags

medialibraryfilesdriveuploadpreviewdrag-dropfolderscms

Dependencies

shadcn primitives: button, context-menu, dialog, input, progress, skeleton
npm peer deps: @dnd-kit/core@^6.3.1, date-fns@^4.1.0, lucide-react@^1.11.0
internal: file-tree, pdf-viewer, code-block, markdown-editor, video-player