All files / components/chat file-preview-panel.tsx

100% Statements 9/9
100% Branches 1/1
100% Functions 3/3
100% Lines 8/8

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67    2x 2x 2x 2x                   7x                                               1x       7x 7x                                            
"use client";
 
import { useMemo } from "react";
import Image from "next/image";
import { XMarkIcon } from "@/components/icons/XMark";
import { MusicalNoteIcon } from "@/components/icons/MusicalNote";
import type { FilePreviewType } from "@/utils/file-type";
 
type FilePreviewPanelProps = {
  file: File;
  type: FilePreviewType;
  onClose: () => void;
};
 
function PreviewContent({ file, type, url }: { file: File; type: FilePreviewType; url: string }) {
  switch (type) {
    case "image":
      return (
        <Image
          src={url}
          alt={file.name}
          width={500}
          height={500}
          unoptimized
          className="h-auto max-h-full w-auto max-w-full rounded-lg object-contain shadow-md"
        />
      );
    case "video":
      return <video src={url} controls className="max-h-full max-w-full rounded-lg shadow-md" />;
    case "audio":
      return (
        <div className="flex w-full max-w-sm flex-col items-center gap-4">
          <div className="flex h-20 w-20 items-center justify-center rounded-2xl bg-amber-500/15 text-amber-400 light:bg-amber-50 light:text-amber-500">
            <MusicalNoteIcon className="size-10" />
          </div>
          <audio src={url} controls className="w-full" />
        </div>
      );
    default:
      return null;
  }
}
 
export function FilePreviewPanel({ file, type, onClose }: FilePreviewPanelProps) {
  const url = useMemo(() => URL.createObjectURL(file), [file]);
 
  return (
    <div className="flex h-full flex-1 flex-col overflow-hidden rounded-[1.75rem] border border-white/9 bg-panel backdrop-blur-[28px] shadow-navy-xl light:border-slate-200 light:shadow-glass-card-light animate-drawer-in">
      <div className="flex items-center justify-between border-b border-white/8 px-5 py-3.5 light:border-slate-200">
        <h4 className="truncate text-sm font-medium text-white/85 light:text-slate-800">{file.name}</h4>
        <button
          type="button"
          aria-label="Close preview"
          onClick={onClose}
          className="ml-4 grid h-7 w-7 shrink-0 place-items-center rounded-lg text-white/40 transition hover:bg-rose-500/15 hover:text-rose-300 light:text-slate-400 light:hover:bg-rose-50 light:hover:text-rose-500"
        >
          <XMarkIcon className="size-4" />
        </button>
      </div>
 
      <div className="min-h-0 flex-1 flex items-center justify-center bg-white/4 p-4 light:bg-slate-100">
        <PreviewContent file={file} type={type} url={url} />
      </div>
    </div>
  );
}