mafzaal commited on
Commit
24bbad4
Β·
1 Parent(s): f6a89c3

Refactor App and Chat components for improved layout and user experience

Browse files

- Updated the App component to enhance layout responsiveness and added flex properties for better alignment.
- Improved the Chat component's structure for consistent styling and overflow handling.
- Introduced thin scrollbar styles in global CSS for a more modern look.
- Enhanced FileManager component with minimum height and improved button styles for better usability.

app/frontend/src/App.js CHANGED
@@ -58,8 +58,8 @@ function App() {
58
 
59
  return (
60
  <ThemeProvider defaultTheme="light">
61
- <div className="min-h-screen bg-background text-foreground transition-colors duration-300">
62
- <header className="bg-primary text-primary-foreground py-4 px-6 shadow-md">
63
  <div className="container mx-auto flex items-center justify-between">
64
  <div className="flex items-center gap-2">
65
  <span role="img" aria-label="brain" className="text-2xl">🧠</span>
@@ -68,65 +68,71 @@ function App() {
68
  <ThemeToggle />
69
  </div>
70
  </header>
71
- <main className="container mx-auto py-6 px-4">
72
- {showUploadForm && (
73
- <FileUpload
74
- sessionId={sessionId}
75
- onUploadSuccess={handleFileUploadSuccess}
76
- />
77
- )}
78
-
79
- {!showUploadForm && uploadedFiles.length > 0 && (
80
- <div className="rounded-lg border border-border bg-card p-6 shadow-sm transition-colors duration-300">
81
- <FileManager
82
- files={uploadedFiles}
83
- activeFileIndex={activeFileIndex}
84
- onSelectFile={handleSelectFile}
85
- onUploadNew={handleUploadNew}
86
  />
87
-
88
- <div className="rounded-md bg-muted p-4 mb-4 transition-colors duration-300">
89
- <h3 className="font-medium mb-2 flex items-center gap-2">
90
- <span role="img" aria-label="document" className="text-xl">
91
- {activeFile.name.toLowerCase().endsWith('.pdf') ? 'πŸ“•' : 'πŸ“„'}
92
- </span>
93
- <span>File: <span className="font-bold">{activeFile.name}</span></span>
94
- </h3>
95
- <p className="text-sm text-muted-foreground">{activeFile.description}</p>
96
- </div>
97
-
98
- {activeFile.suggestedQuestions && activeFile.suggestedQuestions.length > 0 && (
99
- <div className="space-y-2 bg-card p-4 rounded-md border border-border mb-4 transition-colors duration-300">
100
- <h4 className="text-sm font-medium flex items-center gap-2">
101
- <span role="img" aria-label="lightbulb" className="text-xl">πŸ’‘</span>
102
- <span>Suggested questions:</span>
103
- </h4>
104
- <div className="flex flex-wrap gap-2">
105
- {activeFile.suggestedQuestions.map((question, idx) => (
106
- <button
107
- key={idx}
108
- className="text-xs bg-secondary text-secondary-foreground px-3 py-2 rounded-full hover:bg-secondary/80 transition-colors duration-200 flex items-center gap-1"
109
- onClick={() => handleQuestionSelect(question)}
110
- >
111
- <span role="img" aria-label="question" className="text-xs">❓</span>
112
- {question}
113
- </button>
114
- ))}
115
- </div>
116
  </div>
117
- )}
118
-
119
- <Chat
120
- sessionId={activeFile.sessionId}
121
- docDescription={activeFile.description}
122
- suggestedQuestions={activeFile.suggestedQuestions}
123
- selectedQuestion={selectedQuestion}
124
- onQuestionSelected={() => setSelectedQuestion('')}
125
- />
126
- </div>
127
- )}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  </main>
129
- <footer className="container mx-auto py-4 px-6 text-center text-sm text-muted-foreground">
 
130
  <p>Made with <span role="img" aria-label="heart" className="text-red-500">❀️</span> and Shadcn/UI</p>
131
  </footer>
132
  </div>
 
58
 
59
  return (
60
  <ThemeProvider defaultTheme="light">
61
+ <div className="min-h-screen bg-background text-foreground transition-colors duration-300 flex flex-col">
62
+ <header className="bg-primary text-primary-foreground py-4 px-6 shadow-md w-full">
63
  <div className="container mx-auto flex items-center justify-between">
64
  <div className="flex items-center gap-2">
65
  <span role="img" aria-label="brain" className="text-2xl">🧠</span>
 
68
  <ThemeToggle />
69
  </div>
70
  </header>
71
+
72
+ <main className="container mx-auto py-6 px-4 flex-1 flex items-center justify-center">
73
+ <div className="w-full max-w-4xl">
74
+ {showUploadForm && (
75
+ <FileUpload
76
+ sessionId={sessionId}
77
+ onUploadSuccess={handleFileUploadSuccess}
 
 
 
 
 
 
 
 
78
  />
79
+ )}
80
+
81
+ {!showUploadForm && uploadedFiles.length > 0 && (
82
+ <div className="rounded-lg border border-border bg-card p-6 shadow-sm transition-colors duration-300 w-full">
83
+ <FileManager
84
+ files={uploadedFiles}
85
+ activeFileIndex={activeFileIndex}
86
+ onSelectFile={handleSelectFile}
87
+ onUploadNew={handleUploadNew}
88
+ />
89
+
90
+ <div className="rounded-md bg-muted p-4 mb-4 transition-colors duration-300 min-h-[100px]">
91
+ <h3 className="font-medium mb-2 flex items-center gap-2">
92
+ <span role="img" aria-label="document" className="text-xl flex-shrink-0">
93
+ {activeFile.name.toLowerCase().endsWith('.pdf') ? 'πŸ“•' : 'πŸ“„'}
94
+ </span>
95
+ <span className="truncate">File: <span className="font-bold">{activeFile.name}</span></span>
96
+ </h3>
97
+ <p className="text-sm text-muted-foreground line-clamp-3">{activeFile.description}</p>
 
 
 
 
 
 
 
 
 
 
98
  </div>
99
+
100
+ <div className="min-h-[100px] mb-4">
101
+ {activeFile.suggestedQuestions && activeFile.suggestedQuestions.length > 0 && (
102
+ <div className="space-y-2 bg-card p-4 rounded-md border border-border transition-colors duration-300 h-full">
103
+ <h4 className="text-sm font-medium flex items-center gap-2">
104
+ <span role="img" aria-label="lightbulb" className="text-xl flex-shrink-0">πŸ’‘</span>
105
+ <span>Suggested questions:</span>
106
+ </h4>
107
+ <div className="flex flex-wrap gap-2 overflow-y-auto max-h-[100px] pb-1">
108
+ {activeFile.suggestedQuestions.map((question, idx) => (
109
+ <button
110
+ key={idx}
111
+ className="text-xs bg-secondary text-secondary-foreground px-3 py-2 rounded-full hover:bg-secondary/80 transition-colors duration-200 flex items-center gap-1 flex-shrink-0"
112
+ onClick={() => handleQuestionSelect(question)}
113
+ >
114
+ <span role="img" aria-label="question" className="text-xs flex-shrink-0">❓</span>
115
+ <span className="truncate max-w-[200px]">{question}</span>
116
+ </button>
117
+ ))}
118
+ </div>
119
+ </div>
120
+ )}
121
+ </div>
122
+
123
+ <Chat
124
+ sessionId={activeFile.sessionId}
125
+ docDescription={activeFile.description}
126
+ suggestedQuestions={activeFile.suggestedQuestions}
127
+ selectedQuestion={selectedQuestion}
128
+ onQuestionSelected={() => setSelectedQuestion('')}
129
+ />
130
+ </div>
131
+ )}
132
+ </div>
133
  </main>
134
+
135
+ <footer className="w-full py-4 px-6 text-center text-sm text-muted-foreground">
136
  <p>Made with <span role="img" aria-label="heart" className="text-red-500">❀️</span> and Shadcn/UI</p>
137
  </footer>
138
  </div>
app/frontend/src/components/Chat.js CHANGED
@@ -148,8 +148,8 @@ const Chat = ({ sessionId, docDescription, suggestedQuestions, selectedQuestion,
148
  );
149
 
150
  return (
151
- <div className="flex h-[600px] flex-col rounded-lg border border-border bg-card/50 transition-colors duration-300">
152
- <div className="flex-1 overflow-y-auto p-4">
153
  {messages.length === 0 ? (
154
  <div className="flex h-full flex-col items-center justify-center text-center">
155
  <div className="mb-4 rounded-full bg-primary/10 p-6 transition-all duration-300">
@@ -162,45 +162,47 @@ const Chat = ({ sessionId, docDescription, suggestedQuestions, selectedQuestion,
162
  </p>
163
  </div>
164
  ) : (
165
- messages.map((message, index) => (
166
- <div
167
- key={index}
168
- className={`mb-4 flex ${message.sender === 'user' ? 'justify-end' : 'justify-start'}`}
169
- >
170
  <div
171
- className={`
172
- flex items-start gap-2 max-w-[80%] rounded-lg px-4 py-3 shadow-sm
173
- ${message.sender === 'user'
174
- ? 'bg-primary text-primary-foreground'
175
- : message.isError
176
- ? 'bg-destructive text-destructive-foreground'
177
- : 'bg-secondary text-secondary-foreground'
178
- }
179
- transition-all duration-200
180
- `}
181
  >
182
- <span className="mt-1 text-lg">
183
- {message.sender === 'user'
184
- ? 'πŸ‘€'
185
- : message.isError
186
- ? '⚠️'
187
- : 'πŸ€–'}
188
- </span>
189
- <div className={`text-sm ${message.sender === 'ai' ? 'markdown-content' : ''}`}>
190
- {message.sender === 'user' ? (
191
- message.text
192
- ) : (
193
- <MarkdownContent content={message.text} />
194
- )}
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  </div>
196
  </div>
197
- </div>
198
- ))
199
  )}
200
  {isLoading && (
201
- <div className="mb-4 flex justify-start">
202
  <div className="flex items-start gap-2 max-w-[80%] rounded-lg px-4 py-3 bg-secondary text-secondary-foreground shadow-sm">
203
- <span className="mt-1 text-lg">πŸ€–</span>
204
  <div className="flex items-center space-x-2">
205
  <div className="h-2 w-2 animate-bounce rounded-full bg-primary"></div>
206
  <div className="h-2 w-2 animate-bounce rounded-full bg-primary" style={{ animationDelay: '0.2s' }}></div>
@@ -212,8 +214,8 @@ const Chat = ({ sessionId, docDescription, suggestedQuestions, selectedQuestion,
212
  <div ref={messagesEndRef} />
213
  </div>
214
 
215
- <form onSubmit={handleSubmit} className="border-t border-border p-4 transition-colors duration-300">
216
- <div className="flex space-x-2">
217
  <Input
218
  id="chat-input"
219
  ref={inputRef}
@@ -227,10 +229,10 @@ const Chat = ({ sessionId, docDescription, suggestedQuestions, selectedQuestion,
227
  <Button
228
  type="submit"
229
  disabled={isLoading || !input.trim()}
230
- className="transition-colors duration-300 flex items-center gap-2"
231
  >
232
  <span>Send</span>
233
- <span role="img" aria-label="send">πŸ“€</span>
234
  </Button>
235
  </div>
236
  </form>
 
148
  );
149
 
150
  return (
151
+ <div className="flex flex-col rounded-lg border border-border bg-card/50 transition-colors duration-300 h-[600px]">
152
+ <div className="flex-1 overflow-y-auto p-4 w-full">
153
  {messages.length === 0 ? (
154
  <div className="flex h-full flex-col items-center justify-center text-center">
155
  <div className="mb-4 rounded-full bg-primary/10 p-6 transition-all duration-300">
 
162
  </p>
163
  </div>
164
  ) : (
165
+ <div className="w-full">
166
+ {messages.map((message, index) => (
 
 
 
167
  <div
168
+ key={index}
169
+ className={`mb-4 flex ${message.sender === 'user' ? 'justify-end' : 'justify-start'} w-full`}
 
 
 
 
 
 
 
 
170
  >
171
+ <div
172
+ className={`
173
+ flex items-start gap-2 max-w-[80%] rounded-lg px-4 py-3 shadow-sm
174
+ ${message.sender === 'user'
175
+ ? 'bg-primary text-primary-foreground'
176
+ : message.isError
177
+ ? 'bg-destructive text-destructive-foreground'
178
+ : 'bg-secondary text-secondary-foreground'
179
+ }
180
+ transition-all duration-200
181
+ `}
182
+ >
183
+ <span className="mt-1 text-lg flex-shrink-0">
184
+ {message.sender === 'user'
185
+ ? 'πŸ‘€'
186
+ : message.isError
187
+ ? '⚠️'
188
+ : 'πŸ€–'}
189
+ </span>
190
+ <div className={`text-sm ${message.sender === 'ai' ? 'markdown-content' : ''} overflow-hidden`}>
191
+ {message.sender === 'user' ? (
192
+ message.text
193
+ ) : (
194
+ <MarkdownContent content={message.text} />
195
+ )}
196
+ </div>
197
  </div>
198
  </div>
199
+ ))}
200
+ </div>
201
  )}
202
  {isLoading && (
203
+ <div className="mb-4 flex justify-start w-full">
204
  <div className="flex items-start gap-2 max-w-[80%] rounded-lg px-4 py-3 bg-secondary text-secondary-foreground shadow-sm">
205
+ <span className="mt-1 text-lg flex-shrink-0">πŸ€–</span>
206
  <div className="flex items-center space-x-2">
207
  <div className="h-2 w-2 animate-bounce rounded-full bg-primary"></div>
208
  <div className="h-2 w-2 animate-bounce rounded-full bg-primary" style={{ animationDelay: '0.2s' }}></div>
 
214
  <div ref={messagesEndRef} />
215
  </div>
216
 
217
+ <form onSubmit={handleSubmit} className="border-t border-border p-4 transition-colors duration-300 w-full">
218
+ <div className="flex space-x-2 w-full">
219
  <Input
220
  id="chat-input"
221
  ref={inputRef}
 
229
  <Button
230
  type="submit"
231
  disabled={isLoading || !input.trim()}
232
+ className="transition-colors duration-300 flex items-center gap-2 flex-shrink-0"
233
  >
234
  <span>Send</span>
235
+ <span role="img" aria-label="send" className="flex-shrink-0">πŸ“€</span>
236
  </Button>
237
  </div>
238
  </form>
app/frontend/src/components/FileManager.js CHANGED
@@ -5,10 +5,10 @@ const FileManager = ({ files, activeFileIndex, onSelectFile, onUploadNew }) => {
5
  if (!files.length) return null;
6
 
7
  return (
8
- <div className="mb-6">
9
  <div className="flex justify-between items-center mb-3">
10
  <h3 className="text-md font-medium flex items-center gap-2">
11
- <span role="img" aria-label="files" className="text-lg">πŸ“š</span>
12
  <span>Your Documents</span>
13
  </h3>
14
  <Button
@@ -17,28 +17,29 @@ const FileManager = ({ files, activeFileIndex, onSelectFile, onUploadNew }) => {
17
  variant="outline"
18
  className="flex items-center gap-1 text-xs"
19
  >
20
- <span role="img" aria-label="upload">πŸ“„</span>
21
  <span>Upload New</span>
22
  </Button>
23
  </div>
24
 
25
- <div className="overflow-x-auto">
26
- <div className="flex gap-2 pb-2">
27
  {files.map((file, index) => (
28
  <button
29
  key={index}
30
  onClick={() => onSelectFile(index)}
31
  className={`
32
- px-3 py-2 rounded-md text-sm whitespace-nowrap flex items-center gap-1.5 min-w-0 transition-colors
33
  ${activeFileIndex === index
34
  ? 'bg-primary text-primary-foreground'
35
  : 'bg-secondary/70 hover:bg-secondary text-secondary-foreground'}
36
  `}
 
37
  >
38
- <span role="img" aria-label="document" className="flex-none">
39
  {file.name.toLowerCase().endsWith('.pdf') ? 'πŸ“•' : 'πŸ“„'}
40
  </span>
41
- <span className="truncate max-w-[150px]">{file.name}</span>
42
  </button>
43
  ))}
44
  </div>
 
5
  if (!files.length) return null;
6
 
7
  return (
8
+ <div className="mb-6 min-h-[80px]">
9
  <div className="flex justify-between items-center mb-3">
10
  <h3 className="text-md font-medium flex items-center gap-2">
11
+ <span role="img" aria-label="files" className="text-lg flex-shrink-0">πŸ“š</span>
12
  <span>Your Documents</span>
13
  </h3>
14
  <Button
 
17
  variant="outline"
18
  className="flex items-center gap-1 text-xs"
19
  >
20
+ <span role="img" aria-label="upload" className="flex-shrink-0">πŸ“„</span>
21
  <span>Upload New</span>
22
  </Button>
23
  </div>
24
 
25
+ <div className="overflow-x-auto pb-2 scrollbar-thin">
26
+ <div className="flex gap-2 pb-1 min-w-[300px]">
27
  {files.map((file, index) => (
28
  <button
29
  key={index}
30
  onClick={() => onSelectFile(index)}
31
  className={`
32
+ px-3 py-2 rounded-md text-sm whitespace-nowrap flex items-center gap-1.5 min-w-0 flex-shrink-0 transition-colors
33
  ${activeFileIndex === index
34
  ? 'bg-primary text-primary-foreground'
35
  : 'bg-secondary/70 hover:bg-secondary text-secondary-foreground'}
36
  `}
37
+ style={{ minWidth: '120px', maxWidth: '200px' }}
38
  >
39
+ <span role="img" aria-label="document" className="flex-shrink-0">
40
  {file.name.toLowerCase().endsWith('.pdf') ? 'πŸ“•' : 'πŸ“„'}
41
  </span>
42
+ <span className="truncate">{file.name}</span>
43
  </button>
44
  ))}
45
  </div>
app/frontend/src/globals.css CHANGED
@@ -165,4 +165,58 @@
165
  max-width: 100%;
166
  height: auto;
167
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  }
 
165
  max-width: 100%;
166
  height: auto;
167
  }
168
+ }
169
+
170
+ /* Thin scrollbar style */
171
+ .scrollbar-thin::-webkit-scrollbar {
172
+ width: 4px;
173
+ height: 4px;
174
+ }
175
+
176
+ .scrollbar-thin::-webkit-scrollbar-track {
177
+ @apply bg-secondary/30 rounded-full;
178
+ }
179
+
180
+ .scrollbar-thin::-webkit-scrollbar-thumb {
181
+ @apply bg-primary/30 rounded-full transition-colors duration-300;
182
+ }
183
+
184
+ .scrollbar-thin::-webkit-scrollbar-thumb:hover {
185
+ @apply bg-primary/50;
186
+ }
187
+
188
+ /* Make all scrollable areas use the thin scrollbar */
189
+ .overflow-y-auto,
190
+ .overflow-x-auto {
191
+ @apply scrollbar-thin;
192
+ }
193
+
194
+ /* Additional content height limits */
195
+ .line-clamp-3 {
196
+ display: -webkit-box;
197
+ -webkit-line-clamp: 3;
198
+ -webkit-box-orient: vertical;
199
+ overflow: hidden;
200
+ }
201
+
202
+ /* Fix layout shifts with transitions */
203
+ .max-w-md,
204
+ .max-w-4xl,
205
+ .container {
206
+ width: 100%;
207
+ }
208
+
209
+ /* Ensure fixed layout for markdown content */
210
+ .markdown-content img,
211
+ .markdown-content pre,
212
+ .markdown-content table {
213
+ max-width: 100%;
214
+ width: auto !important;
215
+ overflow-x: auto;
216
+ }
217
+
218
+ /* Prevent layout shifts when switching files */
219
+ button, a {
220
+ backface-visibility: hidden;
221
+ transform: translateZ(0);
222
  }