Farigh UI Logo

Farigh UI

Installation

npx shadcn@latest add select
npm install lucide-react

Source Code

background-coding-agent.tsx
1import { useState, useEffect } from 'react'
2import { Folder, GitBranch, GitBranchPlus, GitMerge, CheckCircle2 } from 'lucide-react'
3import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
4
5interface Task {
6    id: number;
7    title: string;
8    date: string;
9    status?: 'Open' | 'Merged' | 'Done';
10    changes: string;
11    statusColor?: 'green' | 'purple' | 'gray';
12}
13
14interface ProcessingTaskState {
15    id: number | null;
16    status: string;
17}
18
19const initialTasks: Task[] = [
20    {
21        id: 4,
22        title: 'Look at my config in sudo_documentation and import terminal sizes from terminal_emulator',
23        date: '',
24        changes: '+93 -58',
25    },
26    {
27        id: 1,
28        title: 'Scan the entire repository and flag any variables, parameters, or properties whose n...',
29        date: 'May 2 · monorepo',
30        status: 'Open',
31        changes: '+57 -27',
32        statusColor: 'green'
33    },
34    {
35        id: 2,
36        title: 'Convert non-critical components to React.lazy with Suspense fallbacks',
37        date: '2 hours ago · monorepo',
38        status: 'Merged',
39        changes: '+134 -45',
40        statusColor: 'purple'
41    },
42    {
43        id: 3,
44        title: 'Create a CI workflow that runs ESLint on every PR and blocks on violations...',
45        date: '2 hours ago · monorepo',
46        changes: '+89 -33',
47    }
48];
49
50const archivedTasksData: Task[] = [
51    {
52        id: 5,
53        title: 'Refactor old class components to functional components with hooks',
54        date: 'Apr 28 · monorepo',
55        status: 'Done',
56        changes: '+250 -112',
57        statusColor: 'gray'
58    },
59    {
60        id: 6,
61        title: 'Update all deprecated dependencies and resolve peer dependency warnings',
62        date: 'Apr 25 · monorepo',
63        status: 'Done',
64        changes: '+15 -9',
65        statusColor: 'gray'
66    }
67];
68
69const ShimmerStyle = () => (
70    <style>{`
71        @keyframes shimmer {
72            0% { background-position: -200% 0; }
73            100% { background-position: 200% 0; }
74        }
75        .shimmer-text {
76            background-image: linear-gradient(to right, #a0a0a0 20%, #e5e7eb 50%, #a0a0a0 80%);
77            background-size: 200% auto;
78            color: transparent;
79            background-clip: text;
80            -webkit-background-clip: text;
81            animation: shimmer 2s linear infinite;
82        }
83    `}</style>
84);
85
86const BackgroundCodingAgent = () => {
87    const [input, setInput] = useState('')
88    const [activeTab, setActiveTab] = useState('Tasks')
89    const [selectedRepo, setSelectedRepo] = useState('monorepo')
90    const [selectedBranch, setSelectedBranch] = useState('main')
91
92    const [tasks, setTasks] = useState<Task[]>(initialTasks);
93    const [archivedTasks, setArchivedTasks] = useState<Task[]>(archivedTasksData);
94
95    const [isProcessing, setIsProcessing] = useState(false);
96    const [processingTask, setProcessingTask] = useState<ProcessingTaskState>({ id: null, status: '' });
97
98    const displayedTasks = activeTab === 'Tasks' ? tasks : archivedTasks;
99
100    const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
101
102    useEffect(() => {
103        const runSimulation = async () => {
104            const targetTaskId = 4;
105            const taskToProcess = tasks.find(t => t.id === targetTaskId);
106            if (!taskToProcess || taskToProcess.status) return;
107
108            setIsProcessing(true);
109
110            const statusUpdates = [
111                { text: 'Analyzing request...', duration: 1500 },
112                { text: 'Scanning files...', duration: 2000 },
113                { text: 'Implementing changes...', duration: 2500 },
114                { text: 'Fixing linting issues...', duration: 1800 },
115                { text: 'Running tests...', duration: 2000 },
116                { text: 'Pushing to branch...', duration: 1500 },
117            ];
118
119            for (const update of statusUpdates) {
120                setProcessingTask({ id: targetTaskId, status: update.text });
121                await delay(update.duration);
122            }
123
124            setTasks(prevTasks =>
125                prevTasks.map(task =>
126                    task.id === targetTaskId
127                        ? {
128                            ...task,
129                            status: 'Open',
130                            statusColor: 'green',
131                            date: 'Just now · monorepo',
132                        }
133                        : task
134                )
135            );
136
137            setProcessingTask({ id: null, status: '' });
138            setIsProcessing(false);
139        };
140
141        runSimulation();
142    }, []);
143
144    return (
145        <div className='min-h-screen bg-white flex items-center justify-center p-4 font-inter'>
146            <ShimmerStyle />
147            <div className='relative w-full max-w-5xl rounded-3xl p-8 space-y-6'>
148                <div className='text-center'>
149                    <h2 className='text-2xl font-semibold text-gray-900'>What should we code next?</h2>
150                </div>
151
152                <div className='space-y-4'>
153                    <div className='border border-gray-200 rounded-3xl p-4'>
154                        <textarea
155                            value={input}
156                            onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setInput(e.target.value)}
157                            placeholder='In my current project, find a bug in the last 5 commits and fix it!'
158                            className='w-full bg-transparent resize-none outline-none text-sm text-gray-700 placeholder-gray-400 font-inter'
159                            rows={3}
160                        />
161
162                        <div className='flex items-center justify-between mt-4 pt-4'>
163                            <div className='flex gap-2'>
164                                <Select value={selectedRepo} onValueChange={setSelectedRepo}>
165                                    <SelectTrigger className='flex items-center justify-center gap-2 px-3 py-1 rounded-full border border-gray-300 bg-white hover:bg-gray-50 text-sm text-gray-700 transition w-auto focus:ring-0'>
166                                        <Folder className='w-4 h-4' />
167                                        <SelectValue placeholder="Select repo" />
168                                    </SelectTrigger>
169                                    <SelectContent>
170                                        <SelectItem value="monorepo">monorepo</SelectItem>
171                                        <SelectItem value="frontend-app">frontend-app</SelectItem>
172                                        <SelectItem value="backend-api">backend-api</SelectItem>
173                                    </SelectContent>
174                                </Select>
175                                <Select value={selectedBranch} onValueChange={setSelectedBranch}>
176                                    <SelectTrigger className='flex items-center justify-center gap-2 px-3 py-1 rounded-full border border-gray-300 bg-white hover:bg-gray-50 text-sm text-gray-700 transition w-auto focus:ring-0'>
177                                        <GitBranch className='w-4 h-4' />
178                                        <SelectValue placeholder="Select branch" />
179                                    </SelectTrigger>
180                                    <SelectContent>
181                                        <SelectItem value="main">main</SelectItem>
182                                        <SelectItem value="develop">develop</SelectItem>
183                                        <SelectItem value="feat/new-ui">feat/new-ui</SelectItem>
184                                    </SelectContent>
185                                </Select>
186                            </div>
187                            <div className='flex gap-2'>
188                                <button className='px-4 py-1 rounded-full border border-gray-300 bg-white hover:bg-gray-50 text-sm text-gray-700 transition'>
189                                    Ask
190                                </button>
191                                <button
192                                    disabled={isProcessing}
193                                    className='px-4 py-1 rounded-full bg-black text-white text-sm hover:bg-gray-800 transition font-medium disabled:bg-gray-400 disabled:cursor-not-allowed'
194                                >
195                                    Code
196                                </button>
197                            </div>
198                        </div>
199                    </div>
200                </div>
201
202                <div className='space-y-3'>
203                    <div className='flex gap-4 border-b border-gray-200'>
204                        <button
205                            onClick={() => setActiveTab('Tasks')}
206                            className={`px-3 py-2 text-sm font-medium transition border-b-2 ${activeTab === 'Tasks'
207                                ? 'text-gray-900 border-gray-900'
208                                : 'text-gray-400 hover:text-gray-700 border-transparent'
209                                }`}
210                        >
211                            Tasks
212                        </button>
213                        <button
214                            onClick={() => setActiveTab('Archive')}
215                            className={`px-3 py-2 text-sm font-medium transition border-b-2 ${activeTab === 'Archive'
216                                ? 'text-gray-900 border-gray-900'
217                                : 'text-gray-400 hover:text-gray-700 border-transparent'
218                                }`}
219                        >
220                            Archive
221                        </button>
222                    </div>
223
224                    <div className='space-y-3'>
225                        {displayedTasks.map((task) => (
226                            <div key={task.id} className='flex items-center justify-between p-3 hover:bg-gray-50 rounded-lg transition group cursor-pointer border border-transparent hover:border-gray-200'>
227                                <div className='flex-1 space-y-1 pr-4'>
228                                    <p className='text-sm text-gray-700 group-hover:text-gray-900'>{task.title}</p>
229                                    <p className='text-xs text-gray-400'>{task.date}</p>
230                                </div>
231                                <div className='flex items-center gap-3'>
232                                    {task.id === processingTask.id ? (
233                                        <span className='text-sm font-medium shimmer-text'>
234                                            {processingTask.status}
235                                        </span>
236                                    ) : task.status && (
237                                        <span className={`flex items-center gap-2 px-3 py-1.5 rounded-full text-xs font-medium ${task.statusColor === 'green' ? 'bg-green-100 text-green-700' :
238                                            task.statusColor === 'purple' ? 'bg-purple-100 text-purple-700' :
239                                                'bg-gray-100 text-gray-600'
240                                            }`}>
241                                            {task.status === 'Open' && <GitBranchPlus className='w-4 h-4' />}
242                                            {task.status === 'Merged' && <GitMerge className='w-4 h-4' />}
243                                            {task.status === 'Done' && <CheckCircle2 className='w-4 h-4' />}
244                                            {task.status}
245                                        </span>
246                                    )}
247                                    {task.id !== processingTask.id && (
248                                        <span className='text-xs font-mono font-semibold whitespace-nowrap'>
249                                            {(() => {
250                                                const parts = task.changes.split(' ');
251                                                const additions = parts.find(p => p.startsWith('+'));
252                                                const deletions = parts.find(p => p.startsWith('-'));
253                                                return (
254                                                    <>
255                                                        {additions && <span className="text-green-600">{additions}</span>}
256                                                        {deletions && <span className={`text-red-600 ${additions ? 'ml-2' : ''}`}>{deletions}</span>}
257                                                    </>
258                                                );
259                                            })()}
260                                        </span>
261                                    )}
262                                </div>
263                            </div>
264                        ))}
265                    </div>
266                </div>
267            </div>
268        </div>
269    )
270}
271
272export default BackgroundCodingAgent;

Related

Flight Card - San Francisco - Free React component preview

Flight Card - San Francisco

Flight Card - New York - Free React component preview

Flight Card - New York

Simplified Pricing - Free React component preview

Simplified Pricing

Mental Pricing - Free React component preview

Mental Pricing