Openinary File Uploader
openinary/file-uploaderFreeBlock
Secure drag-and-drop file uploader for self-hosted Openinary instances. Uploads with a short-lived presigned signature from POST /upload/sign, no API key in the browser.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/openinary/openinary/main/r/file-uploader.jsonSource
1"use client";23import * as React from "react";4import {5 AlertCircle,6 CheckCircle2,7 File as FileIcon,8 Film,9 ImageIcon,10 RotateCw,11 UploadCloud,12 X,13} from "lucide-react";1415import { cn } from "@/lib/utils";16import { Button } from "@/components/ui/button";17import { Progress } from "@/components/ui/progress";18import {19 DEFAULT_ACCEPT,20 DEFAULT_MAX_SIZE,21 useFileUpload,22 type FileUploadState,23 type SignedUpload,24 type UploadFileError,25 type UploadedFile,26} from "@/components/openinary/use-file-upload";2728export interface FileUploaderProps {29 /** Base URL of the Openinary API, e.g. https://media.example.com. Falls back to NEXT_PUBLIC_OPENINARY_URL. */30 baseUrl?: string;31 /**32 * Returns a presigned upload signature from your backend (which calls33 * `POST /upload/sign` with an Openinary API key). Called before each upload34 * batch and on retry. The upload's destination folder is whatever the35 * signature is scoped to.36 */37 sign: () => Promise<SignedUpload> | SignedUpload;38 /** Allow selecting multiple files. Default true. */39 multiple?: boolean;40 /** Accepted MIME types mapped to extensions. Defaults to the Openinary media types. */41 accept?: Record<string, string[]>;42 /** Max file size in bytes. Default 50MB. */43 maxSize?: number;44 /** Client-side cap on the number of files. Not enforced by the server. */45 maxFiles?: number;46 /** Transformation segments to pre-warm, e.g. ["w_800,f_webp"]. */47 transformations?: string[];48 /** Upload automatically as soon as files are added. Default false. */49 autoUpload?: boolean;50 disabled?: boolean;51 className?: string;52 onSuccess?: (files: UploadedFile[]) => void;53 onError?: (error: UploadFileError) => void;54 onProgress?: (file: FileUploadState, progress: number) => void;55}5657function formatBytes(bytes: number): string {58 if (bytes < 1024) return `${bytes} B`;59 if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;60 return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;61}6263function acceptAttribute(accept: Record<string, string[]>): string {64 return Array.from(new Set(Object.values(accept).flat())).join(",");65}6667function FileThumbnail({ file }: { file: FileUploadState }) {68 if (file.previewUrl) {69 return (70 // eslint-disable-next-line @next/next/no-img-element71 <img72 src={file.previewUrl}73 alt={file.name}74 className="size-10 shrink-0 rounded-md object-cover"75 />76 );77 }78 const Icon = file.file.type.startsWith("video/")79// … truncated
What it pulls in
npm packages
Other registry items
