feat(docs-ui): shared FileIcon + signed-state pill on EntityFolderView rows

- Extract FileIcon mapping to `src/components/files/file-icon.tsx` (single
  source of truth for mime→icon+colour palette; was previously inline in
  FileGrid only).
- EntityFolderView file rows now render the type-specific icon (PDF/red,
  Image/blue, Sheet/green, Video/purple) instead of a generic FileText —
  multi-deal clients become scannable at a glance.
- Add an inline "Signed" pill on rows where signedFromDocumentId is set so
  reps can distinguish a signed-from-workflow copy from a vanilla upload
  without hovering for "View signing details".
- Tighter hover treatment (row picks up a subtle bg on hover) for affordance.
- FileGrid refactored to consume the shared FileIcon so both surfaces stay
  in lockstep on future mime additions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-25 13:02:38 +02:00
parent 65b92cace1
commit dd6e8ee968
2 changed files with 15 additions and 25 deletions

View File

@@ -7,6 +7,7 @@ import { ClipboardSignature, FileText, Eye, Download } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { AggregatedSection } from './aggregated-section';
import { SigningDetailsDialog } from './signing-details-dialog';
import { FileIcon } from '@/components/files/file-icon';
import { FilePreviewDialog } from '@/components/files/file-preview-dialog';
import { useAggregatedFiles, useAggregatedWorkflows } from '@/hooks/use-aggregated-listing';
import { StatusPill, type StatusPillStatus } from '@/components/ui/status-pill';
@@ -95,15 +96,23 @@ export function EntityFolderView({ portSlug, entityType, entityId }: Props) {
renderRow={(f: AggregatedFile, _group: AggregatedGroup<AggregatedFile>) => {
const signedFromDocumentId = f.signedFromDocumentId;
return (
<div className="group flex items-center justify-between gap-3 text-sm">
<div className="group flex items-center justify-between gap-3 rounded-sm px-1 py-0.5 text-sm hover:bg-accent/30">
<button
type="button"
className="flex min-w-0 flex-1 items-center gap-2 text-left hover:text-brand focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand/40 rounded-sm"
onClick={() => setPreviewFile({ id: f.id, name: f.filename, mimeType: f.mimeType })}
aria-label={`Preview ${f.filename}`}
>
<FileText className="h-3.5 w-3.5 shrink-0 text-muted-foreground" aria-hidden />
<FileIcon mimeType={f.mimeType} />
<span className="truncate group-hover:underline">{f.filename}</span>
{signedFromDocumentId ? (
<span
className="ml-1 inline-flex shrink-0 items-center rounded-full bg-emerald-50 px-1.5 py-px text-[10px] font-medium text-emerald-700 dark:bg-emerald-950/40 dark:text-emerald-300"
title="This file is a signed copy of a Documenso/uploaded workflow"
>
Signed
</span>
) : null}
{f.interestBerthLabel && f.interestId ? (
<Link
href={`/${portSlug}/interests/${f.interestId}`}

View File

@@ -1,17 +1,10 @@
'use client';
import {
Download,
FileText,
Film,
Image,
MoreHorizontal,
Pencil,
Sheet,
Trash2,
} from 'lucide-react';
import { Download, FileText, MoreHorizontal, Pencil, Trash2 } from 'lucide-react';
import { format } from 'date-fns';
import { FileIcon as SharedFileIcon } from './file-icon';
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
@@ -56,19 +49,7 @@ function formatBytes(bytes: string | null): string {
}
function FileIcon({ mimeType }: { mimeType: string | null }) {
if (!mimeType) return <FileText className="h-8 w-8 text-muted-foreground" />;
// eslint-disable-next-line jsx-a11y/alt-text
if (mimeType.startsWith('image/')) return <Image className="h-8 w-8 text-blue-500" />;
if (mimeType === 'application/pdf') return <FileText className="h-8 w-8 text-red-500" />;
if (
mimeType === 'application/vnd.ms-excel' ||
mimeType === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' ||
mimeType === 'text/csv'
) {
return <Sheet className="h-8 w-8 text-green-600" />;
}
if (mimeType.startsWith('video/')) return <Film className="h-8 w-8 text-purple-500" />;
return <FileText className="h-8 w-8 text-muted-foreground" />;
return <SharedFileIcon mimeType={mimeType} className="h-8 w-8" />;
}
export function FileGrid({