edwarddddr commited on
Commit
fbf128e
·
verified ·
1 Parent(s): 75d9fe1

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +437 -318
index.html CHANGED
@@ -3,7 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>NOVA | AI Companion</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
9
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
@@ -11,53 +11,47 @@
11
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
12
  <style>
13
  :root {
14
- --primary: #6366f1;
15
- --secondary: #8b5cf6;
 
16
  }
17
 
18
- @keyframes float {
19
- 0% { transform: translateY(0px); }
20
- 50% { transform: translateY(-10px); }
21
- 100% { transform: translateY(0px); }
22
  }
23
 
24
- .animate-float {
25
- animation: float 3s ease-in-out infinite;
26
- }
27
-
28
- .gradient-text {
29
- background: linear-gradient(90deg, var(--primary), var(--secondary));
30
- -webkit-background-clip: text;
31
- background-clip: text;
32
- color: transparent;
33
  }
34
 
35
- .message-enter {
36
- opacity: 0;
37
- transform: translateY(10px);
38
  }
39
 
40
- .message-enter-active {
41
- opacity: 1;
42
- transform: translateY(0);
43
- transition: all 300ms ease-out;
44
  }
45
 
46
  .sidebar-transition {
47
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
48
  }
49
 
50
- .custom-scrollbar::-webkit-scrollbar {
51
- width: 6px;
52
  }
53
 
54
- .custom-scrollbar::-webkit-scrollbar-track {
55
- background: rgba(0, 0, 0, 0.05);
 
56
  }
57
 
58
- .custom-scrollbar::-webkit-scrollbar-thumb {
59
- background: rgba(0, 0, 0, 0.2);
60
- border-radius: 3px;
 
61
  }
62
  </style>
63
  </head>
@@ -67,53 +61,143 @@
67
  <script type="text/babel">
68
  const { useState, useEffect, useRef } = React;
69
 
70
- const Navbar = ({ toggleSidebar }) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  return (
72
- <header className="bg-white border-b border-gray-200 px-6 py-4 flex items-center justify-between sticky top-0 z-10">
73
  <div className="flex items-center space-x-4">
74
  <button
75
  onClick={toggleSidebar}
76
- className="md:hidden text-gray-500 hover:text-gray-700 focus:outline-none"
77
  >
78
  <i className="fas fa-bars text-xl"></i>
79
  </button>
80
  <div className="flex items-center">
81
- <div className="w-8 h-8 rounded-full bg-gradient-to-r from-indigo-500 to-purple-500 flex items-center justify-center text-white">
82
- <i className="fas fa-robot"></i>
83
  </div>
84
- <h1 className="ml-3 text-xl font-bold gradient-text">NOVA</h1>
85
  </div>
86
  </div>
87
  <div className="flex items-center space-x-4">
88
- <button className="text-gray-500 hover:text-gray-700 focus:outline-none">
89
- <i className="fas fa-search"></i>
90
- </button>
91
- <button className="text-gray-500 hover:text-gray-700 focus:outline-none">
92
- <i className="fas fa-cog"></i>
 
 
 
 
 
 
93
  </button>
 
 
 
 
 
 
94
  </div>
95
  </header>
96
  );
97
  };
98
 
99
- const Sidebar = ({ isOpen, closeSidebar }) => {
100
- const [activeTab, setActiveTab] = useState('chat');
 
101
 
102
- const tabs = [
103
- { id: 'chat', icon: 'fa-comment-dots', label: 'Chat' },
104
- { id: 'journal', icon: 'fa-book', label: 'Journal' },
105
- { id: 'resources', icon: 'fa-box-open', label: 'Resources' },
106
- { id: 'automation', icon: 'fa-magic', label: 'Automation' },
107
- { id: 'insights', icon: 'fa-chart-line', label: 'Insights' }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  ];
109
 
 
 
 
 
 
 
 
110
  return (
111
- <aside className={`fixed md:relative inset-y-0 left-0 w-64 bg-white border-r border-gray-200 flex flex-col z-20 sidebar-transition ${isOpen ? 'translate-x-0' : '-translate-x-full'} md:translate-x-0`}>
112
  <div className="p-4 border-b border-gray-200 flex items-center justify-between">
113
- <h2 className="text-lg font-semibold text-gray-800">Navigation</h2>
114
  <button
115
  onClick={closeSidebar}
116
- className="md:hidden text-gray-500 hover:text-gray-700 focus:outline-none"
117
  >
118
  <i className="fas fa-times"></i>
119
  </button>
@@ -122,39 +206,62 @@
122
  <div className="flex-1 overflow-y-auto custom-scrollbar">
123
  <nav className="p-4">
124
  <ul className="space-y-1">
125
- {tabs.map(tab => (
126
- <li key={tab.id}>
127
- <button
128
- onClick={() => setActiveTab(tab.id)}
129
- className={`w-full text-left px-4 py-3 rounded-lg flex items-center transition-colors ${activeTab === tab.id ? 'bg-indigo-50 text-indigo-600' : 'hover:bg-gray-50 text-gray-700'}`}
130
- >
131
- <i className={`fas ${tab.icon} mr-3 ${activeTab === tab.id ? 'text-indigo-500' : 'text-gray-500'}`}></i>
132
- <span className="font-medium">{tab.label}</span>
133
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  </li>
135
  ))}
136
  </ul>
137
  </nav>
138
-
139
- <div className="px-4 pb-4">
140
- <div className="bg-indigo-50 rounded-xl p-4">
141
- <h3 className="text-sm font-medium text-indigo-800 mb-2">Daily Challenge</h3>
142
- <p className="text-xs text-indigo-600 mb-3">Complete 3 journal entries to unlock premium features</p>
143
- <div className="w-full bg-indigo-100 rounded-full h-2">
144
- <div className="bg-indigo-500 h-2 rounded-full" style={{ width: '33%' }}></div>
145
- </div>
146
- </div>
147
- </div>
148
  </div>
149
 
150
  <div className="p-4 border-t border-gray-200">
151
- <div className="flex items-center">
152
- <div className="w-10 h-10 rounded-full bg-gradient-to-r from-indigo-400 to-purple-400 flex items-center justify-center text-white">
153
- <i className="fas fa-user"></i>
154
- </div>
155
- <div className="ml-3">
156
- <p className="text-sm font-medium text-gray-800">Alex Johnson</p>
157
- <p className="text-xs text-gray-500">Premium Member</p>
 
 
158
  </div>
159
  </div>
160
  </div>
@@ -162,235 +269,246 @@
162
  );
163
  };
164
 
165
- const ActionPanel = ({ isOpen, closePanel }) => {
166
- const quickActions = [
167
- { icon: 'fa-plus', label: 'New Task', color: 'text-purple-500' },
168
- { icon: 'fa-calendar', label: 'Schedule', color: 'text-blue-500' },
169
- { icon: 'fa-lightbulb', label: 'Ideas', color: 'text-yellow-500' },
170
- { icon: 'fa-chart-pie', label: 'Analyze', color: 'text-green-500' }
171
- ];
172
-
173
- const recentActivities = [
174
- { icon: 'fa-book', label: 'Journal entry completed', time: '2h ago' },
175
- { icon: 'fa-tasks', label: '3 tasks automated', time: 'Yesterday' },
176
- { icon: 'fa-bolt', label: 'Energy optimized', time: '2 days ago' }
177
- ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
  return (
180
- <aside className={`fixed md:relative inset-y-0 right-0 w-72 bg-white border-l border-gray-200 flex flex-col z-20 sidebar-transition ${isOpen ? 'translate-x-0' : 'translate-x-full'} md:translate-x-0`}>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  <div className="p-4 border-b border-gray-200 flex items-center justify-between">
182
- <h2 className="text-lg font-semibold text-gray-800">Action Panel</h2>
183
- <button
184
- onClick={closePanel}
185
- className="md:hidden text-gray-500 hover:text-gray-700 focus:outline-none"
186
- >
187
- <i className="fas fa-times"></i>
188
  </button>
189
  </div>
190
-
191
- <div className="flex-1 overflow-y-auto custom-scrollbar p-4">
192
- <div className="mb-8">
193
- <h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3">Quick Actions</h3>
194
- <div className="grid grid-cols-2 gap-3">
195
- {quickActions.map((action, index) => (
196
- <button
197
- key={index}
198
- className="bg-gray-50 hover:bg-gray-100 rounded-xl p-3 flex flex-col items-center transition-colors"
199
- >
200
- <div className={`w-10 h-10 rounded-full ${action.color.replace('text', 'bg')} bg-opacity-10 flex items-center justify-center mb-2`}>
201
- <i className={`fas ${action.icon} ${action.color}`}></i>
202
- </div>
203
- <span className="text-xs font-medium text-gray-700">{action.label}</span>
204
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  ))}
206
- </div>
207
- </div>
208
-
209
- <div className="mb-8">
210
- <h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3">Recent Activities</h3>
211
- <div className="space-y-3">
212
- {recentActivities.map((activity, index) => (
213
- <div key={index} className="flex items-start">
214
- <div className="mt-1 mr-3">
215
- <div className="w-8 h-8 rounded-full bg-gray-100 flex items-center justify-center text-gray-500">
216
- <i className={`fas ${activity.icon} text-xs`}></i>
217
- </div>
218
- </div>
219
- <div className="flex-1">
220
- <p className="text-sm font-medium text-gray-800">{activity.label}</p>
221
- <p className="text-xs text-gray-500">{activity.time}</p>
222
- </div>
223
- </div>
224
- ))}
225
- </div>
226
- </div>
227
-
228
- <div>
229
- <h3 className="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3">Personalized Suggestions</h3>
230
- <div className="bg-gradient-to-r from-indigo-50 to-purple-50 rounded-xl p-4">
231
- <p className="text-sm font-medium text-gray-800 mb-2">Based on your patterns:</p>
232
- <ul className="text-xs text-gray-600 space-y-2">
233
- <li className="flex items-start">
234
- <i className="fas fa-check-circle text-indigo-400 mr-2 mt-0.5"></i>
235
- <span>Schedule a weekly review at 4pm Fridays</span>
236
- </li>
237
- <li className="flex items-start">
238
- <i className="fas fa-check-circle text-indigo-400 mr-2 mt-0.5"></i>
239
- <span>Automate your morning routine</span>
240
- </li>
241
- <li className="flex items-start">
242
- <i className="fas fa-check-circle text-indigo-400 mr-2 mt-0.5"></i>
243
- <span>Try the 5-minute journal prompt</span>
244
- </li>
245
- </ul>
246
- </div>
247
- </div>
248
  </div>
249
- </aside>
250
  );
251
  };
252
 
253
- const Message = ({ message, isUser }) => {
254
  return (
255
- <div className={`flex ${isUser ? 'justify-end' : 'justify-start'} mb-4`}>
256
- <div className={`max-w-xs md:max-w-md lg:max-w-lg rounded-2xl p-4 ${isUser ? 'bg-indigo-500 text-white rounded-br-none' : 'bg-white border border-gray-200 rounded-bl-none'}`}>
257
- <div className="flex items-start">
258
- {!isUser && (
259
- <div className="mr-3">
260
- <div className="w-8 h-8 rounded-full bg-gradient-to-r from-indigo-400 to-purple-400 flex items-center justify-center text-white">
261
- <i className="fas fa-robot text-sm"></i>
 
 
 
 
 
 
 
262
  </div>
263
- </div>
264
- )}
265
- <div className="flex-1">
266
- <p className={isUser ? 'text-white' : 'text-gray-800'}>{message.text}</p>
267
- {message.actions && (
268
- <div className="mt-3 flex flex-wrap gap-2">
269
- {message.actions.map((action, index) => (
270
- <button
271
- key={index}
272
- className={`text-xs px-3 py-1 rounded-full ${isUser ? 'bg-indigo-600 text-white' : 'bg-gray-100 text-gray-700'} hover:opacity-90 transition-opacity`}
273
- >
274
- {action}
275
- </button>
276
- ))}
277
  </div>
278
- )}
279
  </div>
280
- </div>
281
- <p className={`text-xs mt-2 ${isUser ? 'text-indigo-200' : 'text-gray-500'}`}>
282
- {new Date(message.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
283
- </p>
284
  </div>
285
  </div>
286
  );
287
  };
288
 
289
- const ChatInput = ({ onSendMessage }) => {
290
- const [input, setInput] = useState('');
291
- const inputRef = useRef(null);
292
-
293
- const handleSubmit = (e) => {
294
- e.preventDefault();
295
- if (input.trim()) {
296
- onSendMessage(input);
297
- setInput('');
298
- }
299
- };
300
 
301
- const handleKeyDown = (e) => {
302
- if (e.key === 'Enter' && !e.shiftKey) {
303
- handleSubmit(e);
304
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  };
306
 
307
- useEffect(() => {
308
- inputRef.current.focus();
309
- }, []);
310
-
311
  return (
312
- <form onSubmit={handleSubmit} className="bg-white border-t border-gray-200 p-4">
313
- <div className="max-w-3xl mx-auto">
314
- <div className="relative">
315
- <textarea
316
- ref={inputRef}
317
- value={input}
318
- onChange={(e) => setInput(e.target.value)}
319
- onKeyDown={handleKeyDown}
320
- placeholder="Message NOVA..."
321
- className="w-full border border-gray-300 rounded-xl py-3 px-4 pr-12 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent resize-none"
322
- rows="1"
323
- />
 
 
 
 
324
  <button
325
- type="submit"
326
- disabled={!input.trim()}
327
- className={`absolute right-3 bottom-3 w-8 h-8 rounded-full flex items-center justify-center ${input.trim() ? 'bg-indigo-500 text-white' : 'bg-gray-200 text-gray-400'}`}
328
  >
329
- <i className="fas fa-paper-plane"></i>
330
  </button>
331
  </div>
332
- <div className="flex items-center justify-between mt-2 px-1">
333
- <div className="flex space-x-2">
334
- <button type="button" className="text-gray-500 hover:text-gray-700">
335
- <i className="fas fa-microphone"></i>
336
- </button>
337
- <button type="button" className="text-gray-500 hover:text-gray-700">
338
- <i className="fas fa-image"></i>
339
- </button>
340
- <button type="button" className="text-gray-500 hover:text-gray-700">
341
- <i className="fas fa-paperclip"></i>
342
- </button>
 
 
 
 
 
 
 
343
  </div>
344
- <p className="text-xs text-gray-500">
345
- NOVA v2.1 · <span className="text-indigo-500">Learning active</span>
346
- </p>
347
  </div>
348
  </div>
349
- </form>
350
  );
351
  };
352
 
353
- const ChatWindow = ({ messages, onSendMessage }) => {
354
- const messagesEndRef = useRef(null);
355
-
356
- useEffect(() => {
357
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
358
- }, [messages]);
 
359
 
360
  return (
361
- <div className="flex-1 overflow-y-auto custom-scrollbar p-4 bg-gray-50">
362
- <div className="max-w-3xl mx-auto">
363
- {/* Welcome message */}
364
- <div className="flex justify-center mb-8">
365
- <div className="bg-white border border-gray-200 rounded-2xl p-6 text-center max-w-md">
366
- <div className="w-16 h-16 rounded-full bg-gradient-to-r from-indigo-400 to-purple-400 flex items-center justify-center text-white mx-auto mb-4 animate-float">
367
- <i className="fas fa-robot text-2xl"></i>
368
- </div>
369
- <h3 className="text-xl font-bold text-gray-800 mb-2">Hello, I'm NOVA</h3>
370
- <p className="text-gray-600 mb-4">Your AI companion for productivity, wellness, and growth. How can I assist you today?</p>
371
- <div className="grid grid-cols-2 gap-2">
372
- <button className="bg-indigo-50 hover:bg-indigo-100 text-indigo-600 text-xs px-3 py-2 rounded-lg">
373
- Journal prompt
374
- </button>
375
- <button className="bg-indigo-50 hover:bg-indigo-100 text-indigo-600 text-xs px-3 py-2 rounded-lg">
376
- Task automation
377
- </button>
378
- <button className="bg-indigo-50 hover:bg-indigo-100 text-indigo-600 text-xs px-3 py-2 rounded-lg">
379
- Resource tips
380
- </button>
381
- <button className="bg-indigo-50 hover:bg-indigo-100 text-indigo-600 text-xs px-3 py-2 rounded-lg">
382
- Energy check
383
- </button>
384
- </div>
385
- </div>
386
- </div>
387
-
388
- {/* Chat messages */}
389
- {messages.map((message, index) => (
390
- <Message key={index} message={message} isUser={message.isUser} />
391
  ))}
392
-
393
- <div ref={messagesEndRef} />
394
  </div>
395
  </div>
396
  );
@@ -398,47 +516,30 @@
398
 
399
  const App = () => {
400
  const [sidebarOpen, setSidebarOpen] = useState(false);
401
- const [panelOpen, setPanelOpen] = useState(false);
402
- const [messages, setMessages] = useState([
403
- {
404
- text: "Welcome back! I've analyzed your patterns and have some personalized suggestions for you today.",
405
- timestamp: new Date(),
406
- isUser: false,
407
- actions: ["View suggestions", "Dismiss"]
408
- }
409
- ]);
410
 
411
- const toggleSidebar = () => setSidebarOpen(!sidebarOpen);
412
- const togglePanel = () => setPanelOpen(!panelOpen);
 
 
 
 
413
 
414
- const handleSendMessage = (text) => {
415
- const userMessage = {
416
- text,
417
- timestamp: new Date(),
418
- isUser: true
419
- };
420
-
421
- setMessages(prev => [...prev, userMessage]);
422
-
423
- // Simulate bot response
424
- setTimeout(() => {
425
- const responses = [
426
- "I understand. Would you like me to help break this down into actionable steps?",
427
- "That's an interesting point. Based on your previous activities, I can suggest some resources.",
428
- "I've logged this in your journal. Would you like to reflect on similar past experiences?",
429
- "I can automate parts of this process for you. Shall I prepare some options?"
430
- ];
431
-
432
- const botMessage = {
433
- text: responses[Math.floor(Math.random() * responses.length)],
434
- timestamp: new Date(),
435
- isUser: false,
436
- actions: ["Yes please", "Not now", "More options"]
437
- };
438
-
439
- setMessages(prev => [...prev, botMessage]);
440
- }, 1000 + Math.random() * 2000);
441
- };
442
 
443
  return (
444
  <div className="flex h-screen overflow-hidden bg-gray-50">
@@ -447,14 +548,32 @@
447
  <div className="flex-1 flex flex-col overflow-hidden">
448
  <Navbar toggleSidebar={toggleSidebar} />
449
 
450
- <div className="flex flex-1 overflow-hidden">
451
- <main className="flex-1 flex flex-col overflow-hidden">
452
- <ChatWindow messages={messages} onSendMessage={handleSendMessage} />
453
- <ChatInput onSendMessage={handleSendMessage} />
454
- </main>
455
-
456
- <ActionPanel isOpen={panelOpen} closePanel={() => setPanelOpen(false)} />
457
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  </div>
459
  </div>
460
  );
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>FinEdge | Accounting System</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
9
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
 
11
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
12
  <style>
13
  :root {
14
+ --primary: #3b82f6;
15
+ --secondary: #10b981;
16
+ --accent: #6366f1;
17
  }
18
 
19
+ .grid-stack {
20
+ display: grid;
21
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
22
+ gap: 1.5rem;
23
  }
24
 
25
+ .custom-scrollbar::-webkit-scrollbar {
26
+ width: 6px;
 
 
 
 
 
 
 
27
  }
28
 
29
+ .custom-scrollbar::-webkit-scrollbar-track {
30
+ background: rgba(0, 0, 0, 0.05);
 
31
  }
32
 
33
+ .custom-scrollbar::-webkit-scrollbar-thumb {
34
+ background: rgba(0, 0, 0, 0.2);
35
+ border-radius: 3px;
 
36
  }
37
 
38
  .sidebar-transition {
39
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
40
  }
41
 
42
+ .fade-in {
43
+ animation: fadeIn 0.3s ease-in;
44
  }
45
 
46
+ @keyframes fadeIn {
47
+ from { opacity: 0; }
48
+ to { opacity: 1; }
49
  }
50
 
51
+ .progress-ring__circle {
52
+ transition: stroke-dashoffset 0.35s;
53
+ transform: rotate(-90deg);
54
+ transform-origin: 50% 50%;
55
  }
56
  </style>
57
  </head>
 
61
  <script type="text/babel">
62
  const { useState, useEffect, useRef } = React;
63
 
64
+ // TypeScript type definitions
65
+ type MenuItem = {
66
+ id: string;
67
+ icon: string;
68
+ label: string;
69
+ subItems?: MenuItem[];
70
+ };
71
+
72
+ type FinancialCard = {
73
+ id: string;
74
+ title: string;
75
+ value: string;
76
+ change: number;
77
+ icon: string;
78
+ color: string;
79
+ };
80
+
81
+ type Transaction = {
82
+ id: string;
83
+ date: string;
84
+ description: string;
85
+ amount: number;
86
+ type: 'income' | 'expense';
87
+ category: string;
88
+ status: 'completed' | 'pending' | 'rejected';
89
+ };
90
+
91
+ type Invoice = {
92
+ id: string;
93
+ client: string;
94
+ amount: number;
95
+ dueDate: string;
96
+ status: 'paid' | 'overdue' | 'pending';
97
+ };
98
+
99
+ type ChartData = {
100
+ labels: string[];
101
+ datasets: {
102
+ label: string;
103
+ data: number[];
104
+ backgroundColor: string[];
105
+ borderColor: string[];
106
+ borderWidth: number;
107
+ }[];
108
+ };
109
+
110
+ // Components
111
+ const Navbar = ({ toggleSidebar }: { toggleSidebar: () => void }) => {
112
  return (
113
+ <header className="bg-white border-b border-gray-200 px-6 py-3 flex items-center justify-between sticky top-0 z-10 shadow-sm">
114
  <div className="flex items-center space-x-4">
115
  <button
116
  onClick={toggleSidebar}
117
+ className="lg:hidden text-gray-500 hover:text-gray-700 focus:outline-none"
118
  >
119
  <i className="fas fa-bars text-xl"></i>
120
  </button>
121
  <div className="flex items-center">
122
+ <div className="w-8 h-8 rounded-full bg-gradient-to-r from-blue-500 to-emerald-400 flex items-center justify-center text-white">
123
+ <i className="fas fa-calculator"></i>
124
  </div>
125
+ <h1 className="ml-3 text-xl font-bold text-blue-600">FinEdge</h1>
126
  </div>
127
  </div>
128
  <div className="flex items-center space-x-4">
129
+ <div className="relative hidden md:block">
130
+ <input
131
+ type="text"
132
+ placeholder="Search transactions, reports..."
133
+ className="pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent text-sm w-64"
134
+ />
135
+ <i className="fas fa-search absolute left-3 top-3 text-gray-400"></i>
136
+ </div>
137
+ <button className="text-gray-500 hover:text-gray-700 focus:outline-none relative">
138
+ <i className="fas fa-bell"></i>
139
+ <span className="absolute top-0 right-0 w-2 h-2 bg-red-500 rounded-full"></span>
140
  </button>
141
+ <div className="flex items-center space-x-2">
142
+ <div className="w-8 h-8 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center">
143
+ <i className="fas fa-user"></i>
144
+ </div>
145
+ <span className="hidden md:inline text-sm font-medium">Admin</span>
146
+ </div>
147
  </div>
148
  </header>
149
  );
150
  };
151
 
152
+ const Sidebar = ({ isOpen, closeSidebar }: { isOpen: boolean, closeSidebar: () => void }) => {
153
+ const [activeMenu, setActiveMenu] = useState('dashboard');
154
+ const [expandedMenus, setExpandedMenus] = useState<Record<string, boolean>>({});
155
 
156
+ const menuItems: MenuItem[] = [
157
+ { id: 'dashboard', icon: 'fa-tachometer-alt', label: 'Dashboard' },
158
+ {
159
+ id: 'accounting',
160
+ icon: 'fa-calculator',
161
+ label: 'Accounting',
162
+ subItems: [
163
+ { id: 'general-ledger', icon: 'fa-book', label: 'General Ledger' },
164
+ { id: 'accounts-payable', icon: 'fa-file-invoice-dollar', label: 'Accounts Payable' },
165
+ { id: 'accounts-receivable', icon: 'fa-hand-holding-usd', label: 'Accounts Receivable' },
166
+ { id: 'banking', icon: 'fa-university', label: 'Banking' },
167
+ ]
168
+ },
169
+ {
170
+ id: 'financial-reports',
171
+ icon: 'fa-chart-bar',
172
+ label: 'Financial Reports',
173
+ subItems: [
174
+ { id: 'balance-sheet', icon: 'fa-balance-scale', label: 'Balance Sheet' },
175
+ { id: 'income-statement', icon: 'fa-file-alt', label: 'Income Statement' },
176
+ { id: 'cash-flow', icon: 'fa-exchange-alt', label: 'Cash Flow' },
177
+ ]
178
+ },
179
+ { id: 'invoicing', icon: 'fa-file-invoice', label: 'Invoicing' },
180
+ { id: 'expenses', icon: 'fa-receipt', label: 'Expenses' },
181
+ { id: 'payroll', icon: 'fa-users', label: 'Payroll' },
182
+ { id: 'tax', icon: 'fa-file-contract', label: 'Tax' },
183
+ { id: 'inventory', icon: 'fa-boxes', label: 'Inventory' },
184
+ { id: 'settings', icon: 'fa-cog', label: 'Settings' },
185
  ];
186
 
187
+ const toggleSubMenu = (menuId: string) => {
188
+ setExpandedMenus(prev => ({
189
+ ...prev,
190
+ [menuId]: !prev[menuId]
191
+ }));
192
+ };
193
+
194
  return (
195
+ <aside className={`fixed lg:relative inset-y-0 left-0 w-64 bg-white border-r border-gray-200 flex flex-col z-20 sidebar-transition ${isOpen ? 'translate-x-0' : '-translate-x-full'} lg:translate-x-0`}>
196
  <div className="p-4 border-b border-gray-200 flex items-center justify-between">
197
+ <h2 className="text-lg font-semibold text-gray-800">Menu</h2>
198
  <button
199
  onClick={closeSidebar}
200
+ className="lg:hidden text-gray-500 hover:text-gray-700 focus:outline-none"
201
  >
202
  <i className="fas fa-times"></i>
203
  </button>
 
206
  <div className="flex-1 overflow-y-auto custom-scrollbar">
207
  <nav className="p-4">
208
  <ul className="space-y-1">
209
+ {menuItems.map(item => (
210
+ <li key={item.id}>
211
+ {item.subItems ? (
212
+ <div>
213
+ <button
214
+ onClick={() => toggleSubMenu(item.id)}
215
+ className={`w-full text-left px-4 py-3 rounded-lg flex items-center justify-between transition-colors ${activeMenu === item.id ? 'bg-blue-50 text-blue-600' : 'hover:bg-gray-50 text-gray-700'}`}
216
+ >
217
+ <div className="flex items-center">
218
+ <i className={`fas ${item.icon} mr-3 ${activeMenu === item.id ? 'text-blue-500' : 'text-gray-500'}`}></i>
219
+ <span className="font-medium">{item.label}</span>
220
+ </div>
221
+ <i className={`fas fa-chevron-down text-xs transition-transform ${expandedMenus[item.id] ? 'transform rotate-180' : ''}`}></i>
222
+ </button>
223
+
224
+ {expandedMenus[item.id] && (
225
+ <ul className="ml-8 mt-1 space-y-1">
226
+ {item.subItems.map(subItem => (
227
+ <li key={subItem.id}>
228
+ <button
229
+ onClick={() => setActiveMenu(subItem.id)}
230
+ className={`w-full text-left px-4 py-2 rounded-lg flex items-center text-sm ${activeMenu === subItem.id ? 'bg-blue-50 text-blue-600' : 'hover:bg-gray-50 text-gray-700'}`}
231
+ >
232
+ <i className={`fas ${subItem.icon} mr-3 ${activeMenu === subItem.id ? 'text-blue-500' : 'text-gray-500'}`}></i>
233
+ {subItem.label}
234
+ </button>
235
+ </li>
236
+ ))}
237
+ </ul>
238
+ )}
239
+ </div>
240
+ ) : (
241
+ <button
242
+ onClick={() => setActiveMenu(item.id)}
243
+ className={`w-full text-left px-4 py-3 rounded-lg flex items-center transition-colors ${activeMenu === item.id ? 'bg-blue-50 text-blue-600' : 'hover:bg-gray-50 text-gray-700'}`}
244
+ >
245
+ <i className={`fas ${item.icon} mr-3 ${activeMenu === item.id ? 'text-blue-500' : 'text-gray-500'}`}></i>
246
+ <span className="font-medium">{item.label}</span>
247
+ </button>
248
+ )}
249
  </li>
250
  ))}
251
  </ul>
252
  </nav>
 
 
 
 
 
 
 
 
 
 
253
  </div>
254
 
255
  <div className="p-4 border-t border-gray-200">
256
+ <div className="bg-blue-50 rounded-lg p-3">
257
+ <div className="flex items-center">
258
+ <div className="w-10 h-10 rounded-full bg-blue-100 text-blue-600 flex items-center justify-center">
259
+ <i className="fas fa-question-circle"></i>
260
+ </div>
261
+ <div className="ml-3">
262
+ <p className="text-sm font-medium text-gray-800">Need help?</p>
263
+ <button className="text-xs text-blue-600 hover:underline">Contact support</button>
264
+ </div>
265
  </div>
266
  </div>
267
  </div>
 
269
  );
270
  };
271
 
272
+ const FinancialCard = ({ title, value, change, icon, color }: FinancialCard) => {
273
+ return (
274
+ <div className="bg-white rounded-xl shadow-sm p-5 border border-gray-200 hover:shadow-md transition-shadow">
275
+ <div className="flex justify-between items-start">
276
+ <div>
277
+ <p className="text-sm font-medium text-gray-500 mb-1">{title}</p>
278
+ <p className="text-2xl font-bold text-gray-800">{value}</p>
279
+ <div className={`flex items-center mt-2 text-sm ${change >= 0 ? 'text-green-500' : 'text-red-500'}`}>
280
+ {change >= 0 ? (
281
+ <i className="fas fa-arrow-up mr-1"></i>
282
+ ) : (
283
+ <i className="fas fa-arrow-down mr-1"></i>
284
+ )}
285
+ <span>{Math.abs(change)}% from last month</span>
286
+ </div>
287
+ </div>
288
+ <div className={`w-12 h-12 rounded-full ${color} bg-opacity-10 flex items-center justify-center`}>
289
+ <i className={`fas ${icon} ${color} text-xl`}></i>
290
+ </div>
291
+ </div>
292
+ </div>
293
+ );
294
+ };
295
+
296
+ const ProgressRing = ({ radius, stroke, progress }: { radius: number, stroke: number, progress: number }) => {
297
+ const normalizedRadius = radius - stroke * 2;
298
+ const circumference = normalizedRadius * 2 * Math.PI;
299
+ const strokeDashoffset = circumference - progress / 100 * circumference;
300
 
301
  return (
302
+ <svg height={radius * 2} width={radius * 2} className="transform -rotate-90">
303
+ <circle
304
+ stroke="currentColor"
305
+ fill="transparent"
306
+ strokeWidth={stroke}
307
+ strokeDasharray={circumference + ' ' + circumference}
308
+ style={{ strokeDashoffset }}
309
+ r={normalizedRadius}
310
+ cx={radius}
311
+ cy={radius}
312
+ className="text-blue-100"
313
+ />
314
+ <circle
315
+ stroke="currentColor"
316
+ fill="transparent"
317
+ strokeWidth={stroke}
318
+ strokeDasharray={circumference + ' ' + circumference}
319
+ style={{ strokeDashoffset }}
320
+ r={normalizedRadius}
321
+ cx={radius}
322
+ cy={radius}
323
+ className="text-blue-500"
324
+ />
325
+ </svg>
326
+ );
327
+ };
328
+
329
+ const TransactionsTable = ({ transactions }: { transactions: Transaction[] }) => {
330
+ return (
331
+ <div className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden">
332
  <div className="p-4 border-b border-gray-200 flex items-center justify-between">
333
+ <h3 className="font-medium text-gray-800">Recent Transactions</h3>
334
+ <button className="text-blue-600 text-sm font-medium hover:underline">
335
+ View all
 
 
 
336
  </button>
337
  </div>
338
+ <div className="overflow-x-auto">
339
+ <table className="min-w-full divide-y divide-gray-200">
340
+ <thead className="bg-gray-50">
341
+ <tr>
342
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
343
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Description</th>
344
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Category</th>
345
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Amount</th>
346
+ <th scope="col" className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
347
+ <th scope="col" className="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
348
+ </tr>
349
+ </thead>
350
+ <tbody className="bg-white divide-y divide-gray-200">
351
+ {transactions.map((transaction) => (
352
+ <tr key={transaction.id} className="hover:bg-gray-50">
353
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{transaction.date}</td>
354
+ <td className="px-6 py-4 whitespace-nowrap">
355
+ <div className="text-sm font-medium text-gray-900">{transaction.description}</div>
356
+ </td>
357
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{transaction.category}</td>
358
+ <td className={`px-6 py-4 whitespace-nowrap text-sm font-medium ${transaction.type === 'income' ? 'text-green-600' : 'text-red-600'}`}>
359
+ {transaction.type === 'income' ? '+' : '-'}${Math.abs(transaction.amount).toFixed(2)}
360
+ </td>
361
+ <td className="px-6 py-4 whitespace-nowrap">
362
+ <span className={`px-2 py-1 text-xs rounded-full ${
363
+ transaction.status === 'completed' ? 'bg-green-100 text-green-800' :
364
+ transaction.status === 'pending' ? 'bg-yellow-100 text-yellow-800' :
365
+ 'bg-red-100 text-red-800'
366
+ }`}>
367
+ {transaction.status.charAt(0).toUpperCase() + transaction.status.slice(1)}
368
+ </span>
369
+ </td>
370
+ <td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
371
+ <button className="text-blue-600 hover:text-blue-900 mr-3">Edit</button>
372
+ <button className="text-gray-600 hover:text-gray-900">View</button>
373
+ </td>
374
+ </tr>
375
  ))}
376
+ </tbody>
377
+ </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
  </div>
379
+ </div>
380
  );
381
  };
382
 
383
+ const InvoicesList = ({ invoices }: { invoices: Invoice[] }) => {
384
  return (
385
+ <div className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden">
386
+ <div className="p-4 border-b border-gray-200 flex items-center justify-between">
387
+ <h3 className="font-medium text-gray-800">Recent Invoices</h3>
388
+ <button className="text-blue-600 text-sm font-medium hover:underline">
389
+ View all
390
+ </button>
391
+ </div>
392
+ <div className="divide-y divide-gray-200">
393
+ {invoices.map((invoice) => (
394
+ <div key={invoice.id} className="p-4 hover:bg-gray-50">
395
+ <div className="flex items-center justify-between">
396
+ <div>
397
+ <p className="font-medium text-gray-900">{invoice.client}</p>
398
+ <p className="text-sm text-gray-500">Due {invoice.dueDate}</p>
399
  </div>
400
+ <div className="text-right">
401
+ <p className="font-medium text-gray-900">${invoice.amount.toFixed(2)}</p>
402
+ <span className={`text-xs px-2 py-1 rounded-full ${
403
+ invoice.status === 'paid' ? 'bg-green-100 text-green-800' :
404
+ invoice.status === 'overdue' ? 'bg-red-100 text-red-800' :
405
+ 'bg-yellow-100 text-yellow-800'
406
+ }`}>
407
+ {invoice.status.charAt(0).toUpperCase() + invoice.status.slice(1)}
408
+ </span>
 
 
 
 
 
409
  </div>
410
+ </div>
411
  </div>
412
+ ))}
 
 
 
413
  </div>
414
  </div>
415
  );
416
  };
417
 
418
+ const FinancialChart = () => {
419
+ const [timeRange, setTimeRange] = useState('month');
 
 
 
 
 
 
 
 
 
420
 
421
+ const data: ChartData = {
422
+ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
423
+ datasets: [
424
+ {
425
+ label: 'Income',
426
+ data: [12000, 19000, 15000, 18000, 21000, 19000, 23000],
427
+ backgroundColor: ['rgba(59, 130, 246, 0.2)'],
428
+ borderColor: ['rgba(59, 130, 246, 1)'],
429
+ borderWidth: 2
430
+ },
431
+ {
432
+ label: 'Expenses',
433
+ data: [8000, 12000, 10000, 9000, 11000, 13000, 10000],
434
+ backgroundColor: ['rgba(239, 68, 68, 0.2)'],
435
+ borderColor: ['rgba(239, 68, 68, 1)'],
436
+ borderWidth: 2
437
+ }
438
+ ]
439
  };
440
 
441
+ // This is a simplified representation - in a real app you would use a charting library
 
 
 
442
  return (
443
+ <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-4">
444
+ <div className="flex items-center justify-between mb-4">
445
+ <h3 className="font-medium text-gray-800">Financial Overview</h3>
446
+ <div className="flex space-x-2">
447
+ <button
448
+ onClick={() => setTimeRange('week')}
449
+ className={`px-3 py-1 text-xs rounded-lg ${timeRange === 'week' ? 'bg-blue-100 text-blue-600' : 'bg-gray-100 text-gray-600'}`}
450
+ >
451
+ Week
452
+ </button>
453
+ <button
454
+ onClick={() => setTimeRange('month')}
455
+ className={`px-3 py-1 text-xs rounded-lg ${timeRange === 'month' ? 'bg-blue-100 text-blue-600' : 'bg-gray-100 text-gray-600'}`}
456
+ >
457
+ Month
458
+ </button>
459
  <button
460
+ onClick={() => setTimeRange('year')}
461
+ className={`px-3 py-1 text-xs rounded-lg ${timeRange === 'year' ? 'bg-blue-100 text-blue-600' : 'bg-gray-100 text-gray-600'}`}
 
462
  >
463
+ Year
464
  </button>
465
  </div>
466
+ </div>
467
+
468
+ <div className="relative h-64">
469
+ {/* This would be replaced with a real chart component */}
470
+ <div className="absolute inset-0 flex items-center justify-center text-gray-300">
471
+ <i className="fas fa-chart-line text-5xl"></i>
472
+ <p className="ml-4">Chart visualization would appear here</p>
473
+ </div>
474
+
475
+ {/* Legend */}
476
+ <div className="absolute bottom-0 left-0 right-0 flex justify-center space-x-4">
477
+ <div className="flex items-center">
478
+ <div className="w-3 h-3 bg-blue-500 rounded-full mr-2"></div>
479
+ <span className="text-xs text-gray-600">Income</span>
480
+ </div>
481
+ <div className="flex items-center">
482
+ <div className="w-3 h-3 bg-red-500 rounded-full mr-2"></div>
483
+ <span className="text-xs text-gray-600">Expenses</span>
484
  </div>
 
 
 
485
  </div>
486
  </div>
487
+ </div>
488
  );
489
  };
490
 
491
+ const QuickActions = () => {
492
+ const actions = [
493
+ { icon: 'fa-file-invoice', label: 'Create Invoice', color: 'bg-blue-100 text-blue-600' },
494
+ { icon: 'fa-receipt', label: 'Record Expense', color: 'bg-purple-100 text-purple-600' },
495
+ { icon: 'fa-exchange-alt', label: 'Bank Transfer', color: 'bg-green-100 text-green-600' },
496
+ { icon: 'fa-file-export', label: 'Export Report', color: 'bg-yellow-100 text-yellow-600' },
497
+ ];
498
 
499
  return (
500
+ <div className="bg-white rounded-xl shadow-sm border border-gray-200 p-4">
501
+ <h3 className="font-medium text-gray-800 mb-4">Quick Actions</h3>
502
+ <div className="grid grid-cols-2 gap-3">
503
+ {actions.map((action, index) => (
504
+ <button
505
+ key={index}
506
+ className={`flex flex-col items-center justify-center p-3 rounded-lg hover:shadow-md transition-shadow ${action.color}`}
507
+ >
508
+ <i className={`fas ${action.icon} text-xl mb-2`}></i>
509
+ <span className="text-xs font-medium">{action.label}</span>
510
+ </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
511
  ))}
 
 
512
  </div>
513
  </div>
514
  );
 
516
 
517
  const App = () => {
518
  const [sidebarOpen, setSidebarOpen] = useState(false);
 
 
 
 
 
 
 
 
 
519
 
520
+ const financialCards: FinancialCard[] = [
521
+ { id: '1', title: 'Total Revenue', value: '$48,526', change: 12.5, icon: 'fa-dollar-sign', color: 'text-green-500' },
522
+ { id: '2', title: 'Total Expenses', value: '$26,143', change: -4.3, icon: 'fa-receipt', color: 'text-red-500' },
523
+ { id: '3', title: 'Profit', value: '$22,383', change: 8.2, icon: 'fa-chart-line', color: 'text-blue-500' },
524
+ { id: '4', title: 'Cash Flow', value: '$15,927', change: 5.7, icon: 'fa-exchange-alt', color: 'text-purple-500' },
525
+ ];
526
 
527
+ const transactions: Transaction[] = [
528
+ { id: '1', date: '2023-06-15', description: 'Website Development', amount: 4500, type: 'income', category: 'Services', status: 'completed' },
529
+ { id: '2', date: '2023-06-14', description: 'Office Rent', amount: 1200, type: 'expense', category: 'Rent', status: 'completed' },
530
+ { id: '3', date: '2023-06-13', description: 'Software Subscription', amount: 299, type: 'expense', category: 'Software', status: 'pending' },
531
+ { id: '4', date: '2023-06-12', description: 'Consulting Fee', amount: 1800, type: 'income', category: 'Services', status: 'completed' },
532
+ { id: '5', date: '2023-06-11', description: 'Marketing Campaign', amount: 750, type: 'expense', category: 'Marketing', status: 'rejected' },
533
+ ];
534
+
535
+ const invoices: Invoice[] = [
536
+ { id: '1', client: 'Acme Corp', amount: 5200, dueDate: '2023-06-20', status: 'pending' },
537
+ { id: '2', client: 'Beta LLC', amount: 3200, dueDate: '2023-06-15', status: 'paid' },
538
+ { id: '3', client: 'Gamma Inc', amount: 2800, dueDate: '2023-06-10', status: 'overdue' },
539
+ { id: '4', client: 'Delta Co', amount: 4100, dueDate: '2023-06-25', status: 'pending' },
540
+ ];
541
+
542
+ const toggleSidebar = () => setSidebarOpen(!sidebarOpen);
 
 
 
 
 
 
 
 
 
 
 
 
543
 
544
  return (
545
  <div className="flex h-screen overflow-hidden bg-gray-50">
 
548
  <div className="flex-1 flex flex-col overflow-hidden">
549
  <Navbar toggleSidebar={toggleSidebar} />
550
 
551
+ <main className="flex-1 overflow-y-auto custom-scrollbar p-6">
552
+ <div className="max-w-7xl mx-auto">
553
+ {/* Financial Overview Cards */}
554
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6">
555
+ {financialCards.map(card => (
556
+ <FinancialCard key={card.id} {...card} />
557
+ ))}
558
+ </div>
559
+
560
+ {/* Main Content Area */}
561
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
562
+ <div className="lg:col-span-2">
563
+ <FinancialChart />
564
+ </div>
565
+ <div>
566
+ <QuickActions />
567
+ </div>
568
+ </div>
569
+
570
+ {/* Bottom Section */}
571
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
572
+ <TransactionsTable transactions={transactions} />
573
+ <InvoicesList invoices={invoices} />
574
+ </div>
575
+ </div>
576
+ </main>
577
  </div>
578
  </div>
579
  );