Skip to content

Commit 2e6b0e0

Browse files
committed
feat: Improve file preview UI and add file size formatting
- Reduced PDF thumbnail scale for better performance - Added file size formatting function with B, KB, and MB units - Enhanced file preview layout with smaller, more compact thumbnails - Improved styling for different file types (images, PDFs, other documents) - Added file name and size display in preview thumbnails
1 parent 9ca8aa6 commit 2e6b0e0

File tree

2 files changed

+50
-19
lines changed

2 files changed

+50
-19
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ project, please check the [project management guide](./PROJECT.md) to get starte
7979
- ✅ Add Starter Template Options (@thecodacus)
8080
- ✅ Perplexity Integration (@meetpateltech)
8181
- ✅ AWS Bedrock Integration (@kunjabijukchhe)
82-
- ✅ Add a "Diff View" to see the changes (@toddyclipsgg)
82+
- ✅ Add "Diff View" to see the changes (@toddyclipsgg)
83+
- ✅ Add files MD, DOCX, TXT and PDF (@toddyclipsgg)
8384
-**HIGH PRIORITY** - Prevent bolt from rewriting files as often (file locking and diffs)
8485
-**HIGH PRIORITY** - Better prompting for smaller LLMs (code window sometimes doesn't start)
8586
-**HIGH PRIORITY** - Run agents in the backend as opposed to a single model call

app/components/chat/FilePreview.tsx

+48-18
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ const FilePreview: React.FC<FilePreviewProps> = ({ files, imageDataList, onRemov
4242

4343
// Render the first page as thumbnail
4444
const page = await pdf.getPage(1);
45-
const viewport = page.getViewport({ scale: 0.5 });
45+
// Reduced scale for smaller thumbnail
46+
const viewport = page.getViewport({ scale: 0.3 });
4647

4748
// Create canvas for the thumbnail
4849
const canvas = document.createElement('canvas');
@@ -121,49 +122,78 @@ const FilePreview: React.FC<FilePreviewProps> = ({ files, imageDataList, onRemov
121122
return pdfThumbnails[key];
122123
};
123124

125+
// Function to format file size
126+
const formatFileSize = (bytes: number): string => {
127+
if (bytes < 1024) {
128+
return bytes + ' B';
129+
}
130+
131+
if (bytes < 1024 * 1024) {
132+
return (bytes / 1024).toFixed(1) + ' KB';
133+
}
134+
135+
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
136+
};
137+
124138
return (
125-
<div className="flex flex-wrap overflow-x-auto -mt-2 gap-2">
139+
<div className="flex flex-wrap overflow-x-auto -mt-1 gap-1.5 ml-1 mb-1">
126140
{files.map((file, index) => (
127141
<div key={file.name + file.size} className="relative">
128-
<div className="relative pt-4 pr-4">
142+
<div className="relative pt-2 pr-2">
129143
{imageDataList[index] === 'loading-image' ? (
130144
// Renders loading indicator for images in process
131-
<div className="flex flex-col items-center justify-center bg-bolt-elements-background-depth-3 rounded-md p-2 min-w-[100px] h-[80px]">
132-
<div className="i-svg-spinners:90-ring-with-bg text-bolt-elements-loader-progress text-xl animate-spin"></div>
133-
<div className="text-xs text-bolt-elements-textSecondary mt-1">Loading...</div>
145+
<div className="flex flex-col items-center justify-center bg-bolt-elements-background-depth-3 rounded-md p-1.5 min-w-[35px] h-[28px] border border-gray-700 shadow-sm">
146+
<div className="i-svg-spinners:90-ring-with-bg text-bolt-elements-loader-progress text-sm animate-spin"></div>
147+
<div className="text-[8px] text-bolt-elements-textSecondary mt-0.5">Loading...</div>
134148
</div>
135149
) : imageDataList[index] && imageDataList[index] !== 'non-image' ? (
136150
// Renders image for already loaded image types
137-
<img src={imageDataList[index]} alt={file.name} className="max-h-20" />
151+
<div className="flex flex-col items-center bg-bolt-elements-background-depth-3 rounded-md p-1.5 border border-gray-700 shadow-sm">
152+
<div className="relative overflow-hidden" style={{ maxWidth: '70px', maxHeight: '45px' }}>
153+
<img
154+
src={imageDataList[index]}
155+
alt={file.name}
156+
className="object-contain max-h-[45px] max-w-[70px]"
157+
/>
158+
</div>
159+
<div className="text-[8px] text-bolt-elements-textSecondary mt-0.5 max-w-[70px] truncate">
160+
{file.name}
161+
</div>
162+
<div className="text-[8px] text-bolt-elements-textTertiary">{formatFileSize(file.size)}</div>
163+
</div>
138164
) : isPdf(file) && getPdfThumbnail(file) ? (
139165
// Renders PDF thumbnail
140-
<div className="flex flex-col items-center justify-center bg-bolt-elements-background-depth-3 rounded-md p-2 min-w-[100px]">
166+
<div className="flex flex-col items-center justify-center bg-bolt-elements-background-depth-3 rounded-md p-1.5 min-w-[35px] border border-gray-700 shadow-sm">
141167
<div className="relative">
142168
<img
143169
src={getPdfThumbnail(file)?.dataUrl}
144170
alt={`${file.name} (page 1)`}
145-
className="max-h-20 border border-gray-700 rounded"
171+
className="max-h-[45px] max-w-[70px] border border-gray-800 rounded object-contain"
146172
/>
147-
<div className="absolute bottom-0 right-0 bg-black bg-opacity-70 text-white text-xs px-1 rounded-tl">
173+
<div className="absolute bottom-0 right-0 bg-black bg-opacity-70 text-white text-[7px] px-0.5 rounded-tl">
148174
{getPdfThumbnail(file)?.pageCount || '?'} pgs
149175
</div>
150176
</div>
151-
<div className="text-xs text-bolt-elements-textSecondary mt-1 max-w-[100px] truncate">{file.name}</div>
152-
<div className="text-xs text-bolt-elements-textTertiary">{(file.size / 1024).toFixed(0)} KB</div>
177+
<div className="text-[8px] text-bolt-elements-textSecondary mt-0.5 max-w-[70px] truncate">
178+
{file.name}
179+
</div>
180+
<div className="text-[8px] text-bolt-elements-textTertiary">{formatFileSize(file.size)}</div>
153181
</div>
154182
) : (
155183
// Renders icon for other file types
156-
<div className="flex flex-col items-center justify-center bg-bolt-elements-background-depth-3 rounded-md p-2 min-w-[100px] h-[80px]">
157-
<div className={`${getFileIcon(file.type)} w-6 h-6 text-bolt-elements-textSecondary`} />
158-
<div className="text-xs text-bolt-elements-textSecondary mt-1 max-w-[100px] truncate">{file.name}</div>
159-
<div className="text-xs text-bolt-elements-textTertiary">{(file.size / 1024).toFixed(0)} KB</div>
184+
<div className="flex flex-col items-center justify-center bg-bolt-elements-background-depth-3 rounded-md p-1.5 min-w-[35px] h-[70px] border border-gray-700 shadow-sm">
185+
<div className={`${getFileIcon(file.type)} w-5 h-5 text-bolt-elements-textSecondary`} />
186+
<div className="text-[8px] text-bolt-elements-textSecondary mt-0.5 max-w-[70px] truncate">
187+
{file.name}
188+
</div>
189+
<div className="text-[8px] text-bolt-elements-textTertiary">{formatFileSize(file.size)}</div>
160190
</div>
161191
)}
162192
<button
163193
onClick={() => onRemove(index)}
164-
className="absolute top-1 right-1 z-10 bg-black rounded-full w-5 h-5 shadow-md hover:bg-gray-900 transition-colors flex items-center justify-center"
194+
className="absolute top-0.5 right-0.5 z-10 bg-black rounded-full w-4 h-4 shadow-md hover:bg-gray-900 transition-colors flex items-center justify-center"
165195
>
166-
<div className="i-ph:x w-3 h-3 text-gray-200" />
196+
<div className="i-ph:x w-2 h-2 text-gray-200" />
167197
</button>
168198
</div>
169199
</div>

0 commit comments

Comments
 (0)