This commit is contained in:
Michael Neale
2026-01-23 17:56:54 +11:00
parent 73fb2792f0
commit 191d5dcc1a
+40 -41
View File
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import { Card, CardContent } from './ui/card';
import { Folder, FileText, Image } from 'lucide-react';
import { FolderGit2, FileText, ImageIcon, FileSpreadsheet, FileType, File } from 'lucide-react';
import { createSession } from '../sessions';
import { useNavigation } from '../hooks/useNavigation';
import { useConfig } from './ConfigContext';
@@ -15,28 +15,39 @@ interface RecentFilesProps {
const TYPE_CONFIG: Record<
RecentItemType,
{
icon: typeof Folder;
icon: typeof File;
color: string;
bgColor: string;
}
> = {
repo: {
icon: Folder,
color: 'text-green-600',
bgColor: 'bg-green-50 dark:bg-green-950',
icon: FolderGit2,
color: 'text-green-600 dark:text-green-400',
bgColor: 'bg-green-100 dark:bg-green-900/50',
},
document: {
icon: FileText,
color: 'text-blue-600',
bgColor: 'bg-blue-50 dark:bg-blue-950',
color: 'text-blue-600 dark:text-blue-400',
bgColor: 'bg-blue-100 dark:bg-blue-900/50',
},
image: {
icon: Image,
color: 'text-purple-600',
bgColor: 'bg-purple-50 dark:bg-purple-950',
icon: ImageIcon,
color: 'text-purple-600 dark:text-purple-400',
bgColor: 'bg-purple-100 dark:bg-purple-900/50',
},
};
function getIconForFile(item: RecentItem) {
if (item.type === 'repo') return FolderGit2;
if (item.type === 'image') return ImageIcon;
const ext = item.name.split('.').pop()?.toLowerCase() || '';
if (['xlsx', 'xls', 'csv'].includes(ext)) return FileSpreadsheet;
if (['pdf'].includes(ext)) return FileType;
if (['md', 'txt', 'doc', 'docx'].includes(ext)) return FileText;
return File;
}
export function RecentFiles({ onSessionStarting }: RecentFilesProps) {
const [recentFiles, setRecentFiles] = useState<RecentItem[]>([]);
const [isLoading, setIsLoading] = useState(true);
@@ -66,7 +77,6 @@ export function RecentFiles({ onSessionStarting }: RecentFilesProps) {
onSessionStarting?.();
try {
// Determine working directory based on item type
const workingDir = item.type === 'repo' ? item.fullPath : undefined;
const session = await createSession(workingDir || '', {
@@ -80,7 +90,6 @@ export function RecentFiles({ onSessionStarting }: RecentFilesProps) {
})
);
// Build the initial prompt based on item type
let initialPrompt = '';
if (item.type === 'image') {
initialPrompt = `Please analyze this image: ${item.fullPath}`;
@@ -103,22 +112,12 @@ export function RecentFiles({ onSessionStarting }: RecentFilesProps) {
if (isLoading) {
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
{[1, 2, 3, 4].map((i) => (
<Card
key={i}
className="w-full py-4 px-4 border-none rounded-xl bg-background-default"
>
<CardContent className="p-0">
<div className="flex items-center gap-3">
<Skeleton className="h-10 w-10 rounded-lg" />
<div className="flex-1">
<Skeleton className="h-4 w-32 mb-2" />
<Skeleton className="h-3 w-48" />
</div>
</div>
</CardContent>
</Card>
<div className="grid grid-cols-2 gap-3">
{[1, 2, 3, 4, 5, 6].map((i) => (
<div key={i} className="flex flex-col items-center gap-3 p-4">
<Skeleton className="h-16 w-16 rounded-2xl" />
<Skeleton className="h-4 w-24" />
</div>
))}
</div>
);
@@ -129,17 +128,17 @@ export function RecentFiles({ onSessionStarting }: RecentFilesProps) {
}
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-2">
{recentFiles.map((item) => {
<div className="grid grid-cols-2 gap-3">
{recentFiles.map((item, index) => {
const config = TYPE_CONFIG[item.type];
const Icon = config.icon;
const Icon = getIconForFile(item);
return (
<Card
key={item.fullPath}
className={`w-full py-4 px-4 border-none rounded-xl bg-background-default cursor-pointer
transition-all duration-200 hover:bg-background-muted hover:scale-[1.01]
${startingItem === item.fullPath ? 'opacity-70' : ''}
className={`w-full py-5 px-4 border-none rounded-2xl bg-background-muted/50 cursor-pointer
transition-all duration-200 hover:bg-background-muted hover:scale-[1.02]
${startingItem === item.fullPath ? 'opacity-70 scale-[0.98]' : ''}
${startingItem && startingItem !== item.fullPath ? 'pointer-events-none opacity-50' : ''}`}
onClick={() => handleItemClick(item)}
role="button"
@@ -149,18 +148,18 @@ export function RecentFiles({ onSessionStarting }: RecentFilesProps) {
handleItemClick(item);
}
}}
style={{ animationDelay: `${index * 0.05}s` }}
>
<CardContent className="p-0">
<div className="flex items-start gap-3">
<div className="flex flex-col items-center text-center gap-3">
<div
className={`flex-shrink-0 w-10 h-10 rounded-lg ${config.bgColor} flex items-center justify-center`}
className={`w-16 h-16 rounded-2xl ${config.bgColor} flex items-center justify-center`}
>
<Icon className={`w-5 h-5 ${config.color}`} />
<Icon className={`w-8 h-8 ${config.color}`} strokeWidth={1.5} />
</div>
<div className="flex-1 min-w-0">
<h4 className="text-sm font-medium truncate">{item.name}</h4>
<p className="text-xs text-text-muted truncate">{item.path}</p>
<p className="text-xs text-text-subtle mt-1">{item.suggestion}</p>
<div className="min-w-0 w-full">
<h3 className="text-sm font-medium truncate">{item.name}</h3>
<p className="text-xs text-text-muted truncate">{item.suggestion}</p>
</div>
</div>
</CardContent>