Ashok75 commited on
Commit
6774dc4
·
verified ·
1 Parent(s): 9f64c94

Upload chat.html

Browse files
Files changed (1) hide show
  1. chat.html +1054 -0
chat.html ADDED
@@ -0,0 +1,1054 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en" data-bs-theme="dark">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>GAKR AI - Chat</title>
7
+ <link rel="stylesheet" href="https://cdn.replit.com/agent/bootstrap-agent-dark-theme.min.css">
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
9
+ <link rel="stylesheet" href="style.css">
10
+ <style>
11
+ /* --- Define CSS Variables (Copy from homepage or ensure in style.css) --- */
12
+ :root {
13
+ /* Default light mode colors (adjust as needed) */
14
+ --gakr-blue: #4285F4;
15
+ --gakr-blue-dark: #1a73e8; /* A slightly darker shade for active states */
16
+ --gakr-blue-light: #e8f0fe; /* A light shade for backgrounds */
17
+ --gakr-grey-text: #5f6368;
18
+ --gakr-grey-hover-bg: rgba(95, 99, 104, 0.1); /* Subtle hover for grey icons */
19
+ }
20
+
21
+ :root[data-bs-theme="dark"] {
22
+ /* Dark mode overrides (adjust based on your bootstrap dark theme vars) */
23
+ --gakr-blue: #8ab4f8; /* Lighter blue for dark mode */
24
+ --gakr-blue-dark: #669df6;
25
+ --gakr-blue-light: rgba(138, 180, 248, 0.1); /* Light blue background with transparency */
26
+ --gakr-grey-text: #bdc1c6;
27
+ --gakr-grey-hover-bg: rgba(189, 193, 198, 0.1);
28
+ /* Ensure --bs-body-bg, --bs-body-color, --bs-border-color etc. are correctly set by bootstrap theme */
29
+ }
30
+
31
+ /* --- Base Chat Layout --- */
32
+ .gemini-chat-layout {
33
+ display: flex;
34
+ flex-direction: column;
35
+ height: 100vh;
36
+ width: 100%;
37
+ background-color: var(--bs-body-bg); /* Use BS var */
38
+ color: var(--bs-body-color); /* Use BS var */
39
+ }
40
+
41
+ .gemini-chat-header {
42
+ padding: 0.75rem 1.5rem;
43
+ display: flex;
44
+ justify-content: space-between;
45
+ align-items: center;
46
+ border-bottom: 1px solid var(--bs-border-color);
47
+ height: 64px;
48
+ }
49
+
50
+ .gemini-logo-area {
51
+ display: flex;
52
+ align-items: center;
53
+ gap: 0.75rem;
54
+ }
55
+
56
+ .gemini-brand-logo {
57
+ width: 24px;
58
+ height: 24px;
59
+ display: flex;
60
+ align-items: center;
61
+ justify-content: center;
62
+ }
63
+
64
+ .gemini-brand-text {
65
+ font-size: 1.25rem;
66
+ font-weight: 500;
67
+ color: var(--gakr-blue);
68
+ }
69
+
70
+ .gemini-chat-wrapper {
71
+ flex: 1;
72
+ overflow: hidden;
73
+ position: relative;
74
+ display: flex;
75
+ flex-direction: column;
76
+ }
77
+
78
+ .gemini-chat-container {
79
+ flex: 1;
80
+ overflow-y: auto;
81
+ padding: 1rem;
82
+ display: flex;
83
+ flex-direction: column;
84
+ gap: 1.5rem;
85
+ width: 100%;
86
+ max-width: 800px;
87
+ margin: 0 auto;
88
+ }
89
+
90
+ .gemini-prompt-area {
91
+ padding: 1rem;
92
+ border-top: 1px solid var(--bs-border-color);
93
+ width: 100%;
94
+ max-width: 800px;
95
+ margin: 0 auto;
96
+ /* --- MODIFIED CSS: Add relative positioning for options container --- */
97
+ position: relative;
98
+ /* --- END MODIFIED CSS --- */
99
+ }
100
+
101
+ .gemini-message {
102
+ display: flex;
103
+ flex-direction: column;
104
+ gap: 0.5rem;
105
+ max-width: 90%;
106
+ }
107
+
108
+ .gemini-message-user {
109
+ align-self: flex-end;
110
+ }
111
+
112
+ .gemini-message-ai {
113
+ align-self: flex-start;
114
+ }
115
+
116
+ .gemini-message-header {
117
+ display: flex;
118
+ align-items: center;
119
+ gap: 0.5rem;
120
+ font-size: 0.85rem;
121
+ color: var(--bs-secondary-color);
122
+ }
123
+
124
+ .gemini-message-avatar {
125
+ width: 24px;
126
+ height: 24px;
127
+ border-radius: 50%;
128
+ display: flex;
129
+ align-items: center;
130
+ justify-content: center;
131
+ font-size: 0.75rem;
132
+ }
133
+
134
+ .gemini-message-content {
135
+ padding: 1rem;
136
+ border-radius: 12px;
137
+ line-height: 1.5;
138
+ /* Ensure text wrapping */
139
+ white-space: pre-wrap;
140
+ word-break: break-word;
141
+ }
142
+
143
+ .gemini-message-user .gemini-message-content {
144
+ background-color: var(--bs-tertiary-bg);
145
+ border-top-right-radius: 4px;
146
+ }
147
+
148
+ .gemini-message-ai .gemini-message-content {
149
+ background-color: rgba(66, 133, 244, 0.1);
150
+ border-top-left-radius: 4px;
151
+ }
152
+
153
+ .gemini-message-user .gemini-message-avatar {
154
+ background-color: var(--bs-tertiary-bg);
155
+ }
156
+
157
+ .gemini-message-ai .gemini-message-avatar {
158
+ background-color: rgba(66, 133, 244, 0.2);
159
+ color: var(--gakr-blue);
160
+ }
161
+
162
+ /* --- MODIFIED CSS FOR INPUT/TEXTAREA AND ACTIONS --- */
163
+ .gemini-input-container {
164
+ position: relative; /* Keep relative */
165
+ border-radius: 24px;
166
+ border: 1px solid var(--bs-border-color);
167
+ background: var(--bs-body-bg);
168
+ padding: 0.75rem 1rem; /* Padding around content */
169
+ display: flex;
170
+ /* --- MODIFIED: align-items to flex-end for textarea --- */
171
+ align-items: flex-end;
172
+ /* --- END MODIFIED --- */
173
+ box-shadow: 0 1px 5px rgba(0,0,0,0.1);
174
+ /* Added focus transition from homepage */
175
+ transition: border-color 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
176
+ flex-wrap: wrap; /* Allow items to wrap when attachments are added */
177
+ gap: 0.5rem; /* Space between attachments and input */
178
+ }
179
+
180
+ /* Style when the container or its children are focused */
181
+ .gemini-input-container:focus-within {
182
+ border-color: var(--gakr-blue);
183
+ box-shadow: 0 1px 8px rgba(66, 133, 244, 0.2);
184
+ background: var(--bs-body-bg);
185
+ }
186
+
187
+ /* Style the textarea (#userInput) */
188
+ .gemini-input { /* Targets the textarea with id="userInput" */
189
+ flex: 1; /* Textarea takes available space */
190
+ border: none;
191
+ background: transparent;
192
+ /* --- MODIFIED: Padding adjustment for textarea (removed initial padding to be controlled by JS) --- */
193
+ padding: 0; /* Changed from 0.5rem 0.5rem */
194
+ /* Removed fixed height: height: 24px; from previous input styles */
195
+ /* Removed fixed max-height: 120px; from chat page styles */
196
+ outline: none;
197
+ color: var(--bs-body-color);
198
+ font-size: 1rem; /* Keep font size */
199
+ resize: none; /* Prevent manual resizing */
200
+ overflow-y: hidden; /* JS manages this */
201
+ line-height: 1.4; /* Adjust line height as needed */
202
+ /* Min/Max height calculation (adjust if 1rem font size differs) */
203
+ min-height: calc(1rem * 1.4); /* Approx height of 1 line */
204
+ max-height: calc(1rem * 1.4 * 5); /* Approx max height (5 lines) */
205
+ box-sizing: border-box; /* Include padding/border in element size */
206
+ white-space: pre-wrap; /* Ensure text wraps */
207
+ word-break: break-word; /* Break long words */
208
+ vertical-align: bottom; /* Align baseline to bottom */
209
+ transition: height 0.3s ease-in-out; /* Animate height change */
210
+ }
211
+
212
+ .gemini-input:focus {
213
+ outline: none;
214
+ }
215
+
216
+
217
+ .gemini-input-actions {
218
+ display: flex;
219
+ /* --- MODIFIED: align-items to flex-end for textarea --- */
220
+ align-items: flex-end;
221
+ /* --- ADDED: padding-bottom to align icons --- */
222
+ padding-bottom: 0px; /* Changed from 0.5rem, controlled by JS */
223
+ /* --- END MODIFIED --- */
224
+ gap: 0.5rem;
225
+ font-size: 1.25rem;
226
+ flex-shrink: 0; /* Prevent shrinking */
227
+ }
228
+
229
+ /* Reusing .gemini-action-button styles for new '+' button */
230
+ .gemini-action-button {
231
+ width: 36px;
232
+ height: 36px;
233
+ border-radius: 50%;
234
+ display: flex;
235
+ align-items: center;
236
+ justify-content: center;
237
+ cursor: pointer;
238
+ color: var(--bs-secondary-color); /* Use BS var */
239
+ /* Added hover/active transitions from homepage */
240
+ transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
241
+ }
242
+
243
+ .gemini-action-button:hover {
244
+ background-color: var(--bs-tertiary-bg); /* Use BS var */
245
+ color: var(--bs-body-color); /* Darken icon color slightly on hover */
246
+ }
247
+
248
+ .gemini-action-button:active {
249
+ transform: scale(0.95); /* Slight press effect */
250
+ background-color: var(--bs-tertiary-bg); /* Keep hover bg on active */
251
+ color: var(--bs-body-color);
252
+ transition: background-color 0s, transform 0.1s; /* Make feedback immediate */
253
+ }
254
+
255
+ .gemini-submit-button {
256
+ color: var(--gakr-blue); /* Use CSS var */
257
+ }
258
+
259
+ /* Specific styles for submit button hover/active */
260
+ .gemini-submit-button:hover {
261
+ background-color: var(--gakr-blue-light); /* Light blue background on hover */
262
+ color: var(--gakr-blue-dark); /* Darker blue icon on hover */
263
+ }
264
+
265
+ .gemini-submit-button:active {
266
+ transform: scale(0.95); /* Slight press effect */
267
+ background-color: var(--gakr-blue-light);
268
+ color: var(--gakr-blue-dark);
269
+ transition: background-color 0s, transform 0.1s;
270
+ }
271
+
272
+ .gemini-submit-button.disabled {
273
+ opacity: 0.5;
274
+ cursor: default;
275
+ /* Ensure transitions are off when disabled to avoid weird states */
276
+ transition: none;
277
+ }
278
+
279
+ .gemini-submit-button.disabled:hover {
280
+ background-color: transparent;
281
+ color: var(--gakr-blue); /* Keep original color when disabled */
282
+ }
283
+ /* --- END MODIFIED CSS --- */
284
+
285
+
286
+ .gemini-typing {
287
+ display: inline-flex;
288
+ align-items: center;
289
+ gap: 4px;
290
+ padding: 0.75rem 1rem;
291
+ border-radius: 12px;
292
+ background-color: rgba(66, 133, 244, 0.1);
293
+ margin-bottom: 1rem;
294
+ align-self: flex-end;
295
+ }
296
+
297
+ .gemini-typing-dot {
298
+ width: 6px;
299
+ height: 6px;
300
+ border-radius: 50%;
301
+ background-color: var(--gakr-blue);
302
+ animation: typing 1.3s infinite ease-in-out;
303
+ }
304
+
305
+ .gemini-typing-dot:nth-child(1) { animation-delay: 0s; }
306
+ .gemini-typing-dot:nth-child(2) { animation-delay: 0.2s; }
307
+ .gemini-typing-dot:nth-child(3) { animation-delay: 0.4s; }
308
+
309
+ @keyframes typing {
310
+ 0%, 100% { transform: translateY(0); }
311
+ 50% { transform: translateY(-4px); }
312
+ }
313
+
314
+ .gemini-welcome {
315
+ text-align: center;
316
+ max-width: 600px;
317
+ margin: 4rem auto;
318
+ }
319
+
320
+ .gemini-welcome-icon {
321
+ font-size: 3rem;
322
+ margin-bottom: 1.5rem;
323
+ color: var(--gakr-blue);
324
+ }
325
+
326
+ .gemini-welcome-title {
327
+ font-size: 2rem;
328
+ margin-bottom: 1rem;
329
+ font-weight: 500;
330
+ }
331
+
332
+ /* Login button styling (from homepage) */
333
+ .gemini-login-button {
334
+ color: var(--gakr-blue);
335
+ text-decoration: none;
336
+ background: transparent;
337
+ border: 1px solid var(--gakr-blue);
338
+ padding: 0.5rem 1rem;
339
+ border-radius: 50px;
340
+ font-size: 0.9rem;
341
+ transition: background-color 0.2s;
342
+ }
343
+
344
+ .gemini-login-button:hover {
345
+ background-color: rgba(66, 133, 244, 0.1);
346
+ }
347
+
348
+ /* Login prompt modal (keep existing) */
349
+ .gemini-login-prompt {
350
+ position: fixed;
351
+ top: 0;
352
+ left: 0;
353
+ width: 100%;
354
+ height: 100%;
355
+ background-color: rgba(0, 0, 0, 0.5);
356
+ display: flex;
357
+ align-items: center;
358
+ justify-content: center;
359
+ z-index: 1000;
360
+ opacity: 0;
361
+ visibility: hidden;
362
+ transition: opacity 0.3s, visibility 0.3s;
363
+ }
364
+
365
+ .gemini-login-prompt.show {
366
+ opacity: 1;
367
+ visibility: visible;
368
+ }
369
+
370
+ .gemini-login-prompt-content {
371
+ background-color: var(--bs-body-bg);
372
+ border-radius: 12px;
373
+ padding: 1.5rem;
374
+ max-width: 400px;
375
+ width: 90%;
376
+ }
377
+
378
+ .gemini-login-prompt-title {
379
+ font-size: 1.25rem;
380
+ font-weight: 500;
381
+ margin-bottom: 1rem;
382
+ color: var(--gakr-blue);
383
+ }
384
+
385
+ .gemini-login-prompt-buttons {
386
+ display: flex;
387
+ flex-direction: column;
388
+ gap: 0.75rem;
389
+ margin-top: 1.5rem;
390
+ }
391
+
392
+ .gemini-button-primary {
393
+ background-color: var(--gakr-blue);
394
+ color: white;
395
+ border: none;
396
+ padding: 0.75rem 1rem;
397
+ border-radius: 50px;
398
+ font-size: 0.9rem;
399
+ text-align: center;
400
+ text-decoration: none;
401
+ cursor: pointer;
402
+ transition: background-color 0.2s;
403
+ }
404
+
405
+ .gemini-button-primary:hover {
406
+ background-color: #3b78e7;
407
+ }
408
+
409
+ .gemini-button-secondary {
410
+ background-color: transparent;
411
+ color: var(--gakr-blue);
412
+ border: 1px solid var(--gakr-blue);
413
+ padding: 0.75rem 1rem;
414
+ border-radius: 50px;
415
+ font-size: 0.9rem;
416
+ text-align: center;
417
+ text-decoration: none;
418
+ cursor: pointer;
419
+ transition: background-color 0.2s;
420
+ }
421
+
422
+ .gemini-button-secondary:hover {
423
+ background-color: rgba(66, 133, 244, 0.1);
424
+ }
425
+
426
+ .gemini-button-text {
427
+ background-color: transparent;
428
+ color: var(--bs-body-color);
429
+ border: none;
430
+ padding: 0.75rem 1rem;
431
+ border-radius: 50px;
432
+ font-size: 0.9rem;
433
+ text-align: center;
434
+ text-decoration: none;
435
+ cursor: pointer;
436
+ transition: background-color 0.2s;
437
+ }
438
+
439
+ .gemini-button-text:hover {
440
+ background-color: var(--bs-tertiary-bg);
441
+ }
442
+
443
+ /* --- NEW CSS for Attachment Options --- */
444
+ .attachment-options-container {
445
+ position: absolute;
446
+ bottom: 100%; /* Position above the input bar */
447
+ left: 1rem; /* Align with left edge padding of prompt area */
448
+ transform: translateY(-10px); /* Slight initial lift */
449
+ z-index: 10; /* Ensure it's above chat messages */
450
+
451
+ background-color: var(--bs-body-bg);
452
+ border: 1px solid var(--bs-border-color);
453
+ border-radius: 15px;
454
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
455
+ padding: 15px;
456
+
457
+ display: flex;
458
+ gap: 20px;
459
+ justify-content: flex-start; /* Align options to the left */
460
+ min-width: max-content;
461
+
462
+ opacity: 0;
463
+ visibility: hidden;
464
+ pointer-events: none; /* Prevent clicks when hidden */
465
+
466
+ transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out, visibility 0s linear 0.3s; /* Animate opacity/transform, hide visibility after */
467
+ }
468
+
469
+ /* State when visible */
470
+ .attachment-options-container.visible {
471
+ opacity: 1;
472
+ visibility: visible;
473
+ pointer-events: auto; /* Allow clicks when visible */
474
+ transform: translateY(-20px); /* Slight slide up effect */
475
+ transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out, visibility 0s linear 0s; /* Show visibility immediately */
476
+ }
477
+
478
+ .attachment-option {
479
+ display: flex;
480
+ flex-direction: column;
481
+ align-items: center;
482
+ cursor: pointer;
483
+ color: var(--bs-body-color);
484
+ font-size: 0.8rem;
485
+ gap: 5px;
486
+ transition: color 0.2s ease-in-out;
487
+ }
488
+
489
+ .attachment-option:hover {
490
+ color: var(--gakr-blue);
491
+ }
492
+
493
+ .attachment-icon {
494
+ width: 48px;
495
+ height: 48px;
496
+ border-radius: 50%;
497
+ background-color: var(--bs-tertiary-bg);
498
+ display: flex;
499
+ align-items: center;
500
+ justify-content: center;
501
+ font-size: 1.2rem;
502
+ transition: background-color 0.2s ease-in-out;
503
+ }
504
+
505
+ .attachment-option:hover .attachment-icon {
506
+ background-color: var(--gakr-blue-light);
507
+ }
508
+
509
+ .attachment-text {
510
+ text-align: center;
511
+ }
512
+
513
+ /* Styles for attached file chips */
514
+ .attached-file-preview-container {
515
+ display: flex;
516
+ flex-wrap: wrap;
517
+ gap: 8px;
518
+ /* Removed padding-bottom from here, handled by JS setting padding-top on textarea */
519
+ width: 100%; /* Take full width of parent container */
520
+ }
521
+
522
+ .attached-file-chip {
523
+ display: flex;
524
+ align-items: center;
525
+ background-color: var(--bs-tertiary-bg);
526
+ border-radius: 16px;
527
+ padding: 4px 8px;
528
+ font-size: 0.85rem;
529
+ color: var(--bs-body-color);
530
+ max-width: 150px; /* Limit chip width */
531
+ overflow: hidden;
532
+ text-overflow: ellipsis;
533
+ white-space: nowrap;
534
+ position: relative; /* For the close button */
535
+ }
536
+
537
+ .attached-file-chip .file-name {
538
+ flex-grow: 1;
539
+ overflow: hidden;
540
+ text-overflow: ellipsis;
541
+ white-space: nowrap;
542
+ padding-right: 8px; /* Space for close button */
543
+ }
544
+
545
+ .attached-file-chip .remove-file {
546
+ cursor: pointer;
547
+ margin-left: 4px;
548
+ color: var(--bs-secondary-color);
549
+ }
550
+
551
+ .attached-file-chip .remove-file:hover {
552
+ color: var(--bs-body-color);
553
+ }
554
+
555
+ .attached-file-chip img {
556
+ width: 24px;
557
+ height: 24px;
558
+ border-radius: 4px;
559
+ object-fit: cover;
560
+ margin-right: 8px;
561
+ }
562
+
563
+ /* Hide file inputs */
564
+ .hidden-file-input {
565
+ display: none;
566
+ }
567
+
568
+
569
+ /* --- END NEW CSS --- */
570
+
571
+ </style>
572
+ </head>
573
+ <body>
574
+ <div class="gemini-chat-layout">
575
+ <header class="gemini-chat-header">
576
+ <div class="gemini-logo-area">
577
+ <a href="/" class="gemini-brand-logo">
578
+ <i class="fas fa-robot" style="color: var(--gakr-blue);"></i>
579
+ </a>
580
+ <a href="/" class="gemini-brand-text" style="text-decoration: none;">GAKR AI</a>
581
+ </div>
582
+
583
+ <div class="gemini-nav-controls">
584
+ <a href="auth.html" class="gemini-login-button">Sign in / Register</a>
585
+ </div>
586
+ </header>
587
+
588
+ <div class="gemini-chat-wrapper">
589
+ <div class="gemini-chat-container" id="chatContainer">
590
+ <div class="gemini-welcome" id="welcomeMessage">
591
+ <div class="gemini-welcome-icon">
592
+ <i class="fas fa-robot"></i>
593
+ </div>
594
+ <h1 class="gemini-welcome-title">How can I help you today?</h1>
595
+ <p>I'm GAKR AI, your AI assistant. Ask me anything!</p>
596
+ </div>
597
+
598
+ <div class="gemini-message gemini-message-ai d-none" id="initialMessage">
599
+ <div class="gemini-message-header">
600
+ <div class="gemini-message-avatar">
601
+ <i class="fas fa-robot"></i>
602
+ </div>
603
+ <span>GAKR AI</span>
604
+ </div>
605
+ <div class="gemini-message-content">Hello! I'm GAKR AI How can I help you today?
606
+ </div>
607
+ </div>
608
+
609
+ <div class="gemini-typing d-none" id="typingIndicator">
610
+ <div class="gemini-typing-dot"></div>
611
+ <div class="gemini-typing-dot"></div>
612
+ <div class="gemini-typing-dot"></div>
613
+ </div>
614
+ </div>
615
+
616
+ <div class="gemini-prompt-area">
617
+ <div class="gemini-input-container" id="inputContainer">
618
+ <div class="gemini-action-button" id="addButton">
619
+ <i class="fas fa-plus"></i>
620
+ </div>
621
+ <div class="attached-file-preview-container" id="attachedFilePreviewContainer">
622
+ </div>
623
+ <textarea class="gemini-input" id="userInput" placeholder="Message GAKR AI..." rows="1"></textarea>
624
+
625
+ <div class="gemini-input-actions">
626
+ <div class="gemini-action-button">
627
+ <i class="fas fa-microphone"></i>
628
+ </div>
629
+ <div class="gemini-action-button gemini-submit-button disabled" id="submitButton">
630
+ <i class="fas fa-arrow-right"></i>
631
+ </div>
632
+ </div>
633
+ </div>
634
+
635
+ <div class="attachment-options-container">
636
+ <div class="attachment-option" id="cameraOption">
637
+ <div class="attachment-icon"><i class="fas fa-camera"></i></div>
638
+ <div class="attachment-text">Camera</div>
639
+ <input type="file" id="cameraInput" class="hidden-file-input" accept="image/*" capture="camera">
640
+ </div>
641
+ <div class="attachment-option" id="galleryOption">
642
+ <div class="attachment-icon"><i class="fas fa-image"></i></div>
643
+ <div class="attachment-text">Gallery</div>
644
+ <input type="file" id="galleryInput" class="hidden-file-input" accept="image/*">
645
+ </div>
646
+ <div class="attachment-option" id="filesOption">
647
+ <div class="attachment-icon"><i class="fas fa-paperclip"></i></div>
648
+ <div class="attachment-text">Files</div>
649
+ <input type="file" id="filesInput" class="hidden-file-input" accept="*/*">
650
+ </div>
651
+ <div class="attachment-option" id="driveOption">
652
+ <div class="attachment-icon"><i class="fab fa-google-drive"></i></div>
653
+ <div class="attachment-text">Drive</div>
654
+ </div>
655
+ </div>
656
+ </div>
657
+ </div>
658
+
659
+ <div class="gemini-login-prompt" id="loginPrompt">
660
+ <div class="gemini-login-prompt-content">
661
+ <div class="gemini-login-prompt-title">Continue with GAKR AI</div>
662
+ <p>You've had 5 conversations with GAKR AI. Would you like to create an account to save your history?</p>
663
+ <div class="gemini-login-prompt-buttons">
664
+ <a href="login.html" class="gemini-button-primary">Sign in</a>
665
+ <a href="/login?signup=true" class="gemini-button-secondary">Create account</a>
666
+ <button type="button" class="gemini-button-text" id="continueGuest">Continue as guest</button>
667
+ </div>
668
+ </div>
669
+ </div>
670
+ </div>
671
+ <script>
672
+ document.addEventListener('DOMContentLoaded', function() {
673
+ const chatContainer = document.getElementById('chatContainer');
674
+ const userInput = document.getElementById('userInput'); // This is the textarea
675
+ const submitButton = document.getElementById('submitButton');
676
+ const typingIndicator = document.getElementById('typingIndicator');
677
+ const welcomeMessage = document.getElementById('welcomeMessage');
678
+ const initialMessage = document.getElementById('initialMessage');
679
+ const loginPrompt = document.getElementById('loginPrompt');
680
+ const continueGuest = document.getElementById('continueGuest');
681
+
682
+ const addButton = document.getElementById('addButton'); // Get the new add button
683
+ const attachmentOptionsContainer = document.querySelector('.attachment-options-container'); // Get the options container
684
+
685
+ // New elements for file handling
686
+ const cameraInput = document.getElementById('cameraInput');
687
+ const galleryInput = document.getElementById('galleryInput');
688
+ const filesInput = document.getElementById('filesInput');
689
+ const attachedFilePreviewContainer = document.getElementById('attachedFilePreviewContainer');
690
+ const inputContainer = document.getElementById('inputContainer'); // The .gemini-input-container
691
+
692
+ let messageCount = 0;
693
+ let attachedFiles = []; // Array to store File objects
694
+
695
+ // --- Textarea Auto-Grow & Scroll Logic (Enhanced) ---
696
+ const style = getComputedStyle(userInput);
697
+ const lineHeight = parseFloat(style.lineHeight);
698
+ const minHeight = lineHeight; // Height for one line of text
699
+ const maxHeight = lineHeight * 5; // Height for 5 lines of text
700
+
701
+ // Initial padding values for the input container, adjusted for icons
702
+ const initialInputContainerPaddingTop = parseFloat(getComputedStyle(inputContainer).paddingTop);
703
+ const initialInputContainerPaddingBottom = parseFloat(getComputedStyle(inputContainer).paddingBottom);
704
+ const initialActionButtonsHeight = document.querySelector('.gemini-input-actions').offsetHeight; // Height of mic/send icons
705
+
706
+ function autoGrowTextarea() {
707
+ if (!userInput) {
708
+ console.error("autoGrowTextarea called but userInput element not found.");
709
+ return;
710
+ }
711
+
712
+ // Reset height to auto to get the true scrollHeight
713
+ userInput.style.height = 'auto';
714
+ const scrollHeight = userInput.scrollHeight;
715
+
716
+ // Calculate actual textarea height based on content, respecting min/max
717
+ let newTextareaHeight = Math.min(Math.max(scrollHeight, minHeight), maxHeight);
718
+ userInput.style.height = newTextareaHeight + 'px';
719
+
720
+ // Adjust padding of the input container if files are present
721
+ if (attachedFiles.length > 0) {
722
+ // The `attachedFilePreviewContainer` already has height, we need space below it for the textarea
723
+ // The overall `inputContainer` needs to grow, and `userInput`'s height is part of that.
724
+ // The gap between chips and textarea is handled by `gap` on `inputContainer`.
725
+ // We need to ensure the textarea's padding is minimal, and its effective content area is what's used.
726
+ userInput.style.paddingTop = '0px';
727
+ userInput.style.paddingBottom = '0px';
728
+ inputContainer.style.alignItems = 'flex-start'; // Align content to the top
729
+ } else {
730
+ // Reset to default alignment and padding if no files
731
+ userInput.style.paddingTop = '0px'; // Controlled by the overall inputContainer padding
732
+ userInput.style.paddingBottom = '0px'; // Controlled by the overall inputContainer padding
733
+ inputContainer.style.alignItems = 'flex-end'; // Align to bottom for default state
734
+ }
735
+
736
+ // Manage overflow-y based on whether it hits max height
737
+ if (scrollHeight > maxHeight) {
738
+ userInput.style.overflowY = 'auto';
739
+ } else {
740
+ userInput.style.overflowY = 'hidden';
741
+ }
742
+
743
+ // Enable submit button if there's text or attached files
744
+ if (userInput.value.trim().length > 0 || attachedFiles.length > 0) {
745
+ submitButton.classList.remove('disabled');
746
+ } else {
747
+ submitButton.classList.add('disabled');
748
+ }
749
+ }
750
+
751
+ userInput.addEventListener('input', autoGrowTextarea);
752
+ // Run on load to set initial height correctly
753
+ setTimeout(autoGrowTextarea, 0);
754
+ // --- End Textarea Auto-Grow & Scroll Logic ---
755
+
756
+
757
+ // Handle Enter key for sending (allow Shift+Enter for new line)
758
+ userInput.addEventListener('keydown', function(event) {
759
+ if (event.key === 'Enter' && !event.shiftKey && !submitButton.classList.contains('disabled')) {
760
+ event.preventDefault();
761
+ sendMessage();
762
+ }
763
+ });
764
+
765
+ // Handle submit button click
766
+ submitButton.addEventListener('click', function() {
767
+ if (!this.classList.contains('disabled')) {
768
+ sendMessage();
769
+ }
770
+ });
771
+
772
+ // Handle continue as guest button click
773
+ continueGuest.addEventListener('click', function() {
774
+ loginPrompt.classList.remove('show');
775
+ });
776
+
777
+ // --- Handle Add Button Click ---
778
+ addButton.addEventListener('click', function(event) {
779
+ event.stopPropagation();
780
+ attachmentOptionsContainer.classList.toggle('visible');
781
+ });
782
+
783
+ // --- Handle Attachment Option Clicks ---
784
+ document.getElementById('cameraOption').addEventListener('click', function() {
785
+ cameraInput.click();
786
+ attachmentOptionsContainer.classList.remove('visible');
787
+ });
788
+
789
+ document.getElementById('galleryOption').addEventListener('click', function() {
790
+ galleryInput.click();
791
+ attachmentOptionsContainer.classList.remove('visible');
792
+ });
793
+
794
+ document.getElementById('filesOption').addEventListener('click', function() {
795
+ filesInput.click();
796
+ attachmentOptionsContainer.classList.remove('visible');
797
+ });
798
+
799
+ document.getElementById('driveOption').addEventListener('click', function() {
800
+ alert("Google Drive integration requires backend setup and Google API access.");
801
+ attachmentOptionsContainer.classList.remove('visible');
802
+ });
803
+
804
+ // --- Handle File Input Change ---
805
+ [cameraInput, galleryInput, filesInput].forEach(input => {
806
+ input.addEventListener('change', function(event) {
807
+ const files = event.target.files;
808
+ if (files.length > 0) {
809
+ for (let i = 0; i < files.length; i++) {
810
+ attachedFiles.push(files[i]);
811
+ addFileChip(files[i]);
812
+ }
813
+ autoGrowTextarea(); // Re-evaluate button state and input height
814
+ userInput.focus(); // Keep focus on the textarea
815
+ }
816
+ // Clear the input so the same file can be selected again
817
+ event.target.value = '';
818
+ });
819
+ });
820
+
821
+ // Function to add a file chip to the input container
822
+ function addFileChip(file) {
823
+ const chip = document.createElement('div');
824
+ chip.className = 'attached-file-chip';
825
+ chip.setAttribute('data-filename', file.name); // Store filename for removal
826
+
827
+ let previewElement;
828
+ if (file.type.startsWith('image/')) {
829
+ const img = document.createElement('img');
830
+ img.src = URL.createObjectURL(file);
831
+ img.alt = file.name;
832
+ img.onload = () => URL.revokeObjectURL(img.src); // Clean up object URL
833
+ previewElement = img;
834
+ } else {
835
+ const icon = document.createElement('i');
836
+ icon.className = 'fas fa-paperclip'; // Generic file icon
837
+ previewElement = icon;
838
+ }
839
+
840
+ const fileNameSpan = document.createElement('span');
841
+ fileNameSpan.className = 'file-name';
842
+ fileNameSpan.textContent = file.name;
843
+
844
+ const removeButton = document.createElement('span');
845
+ removeButton.className = 'remove-file';
846
+ removeButton.innerHTML = '&times;'; // 'x' icon
847
+ removeButton.addEventListener('click', function() {
848
+ removeFileChip(file.name);
849
+ });
850
+
851
+ chip.appendChild(previewElement);
852
+ chip.appendChild(fileNameSpan);
853
+ chip.appendChild(removeButton);
854
+
855
+ attachedFilePreviewContainer.appendChild(chip);
856
+ // No need to set userInput.style.paddingTop here directly,
857
+ // autoGrowTextarea will re-evaluate based on the container's contents.
858
+ autoGrowTextarea(); // Re-run autoGrow to adjust textarea based on new chip height
859
+ }
860
+
861
+ // Function to remove a file chip
862
+ function removeFileChip(filename) {
863
+ const chipToRemove = attachedFilePreviewContainer.querySelector(`[data-filename="${filename}"]`);
864
+ if (chipToRemove) {
865
+ attachedFilePreviewContainer.removeChild(chipToRemove);
866
+ attachedFiles = attachedFiles.filter(file => file.name !== filename);
867
+ autoGrowTextarea(); // Re-evaluate button state and input height
868
+ }
869
+ }
870
+
871
+
872
+ // --- Hide options when clicking outside ---
873
+ document.addEventListener('click', function(event) {
874
+ const isClickInsideAddButton = addButton && addButton.contains(event.target);
875
+ const isClickInsideOptions = attachmentOptionsContainer && attachmentOptionsContainer.contains(event.target);
876
+
877
+ if (attachmentOptionsContainer && attachmentOptionsContainer.classList.contains('visible') && !isClickInsideAddButton && !isClickInsideOptions) {
878
+ attachmentOptionsContainer.classList.remove('visible');
879
+ }
880
+ });
881
+
882
+ if (attachmentOptionsContainer) {
883
+ attachmentOptionsContainer.addEventListener('click', function(event){
884
+ event.stopPropagation();
885
+ });
886
+ }
887
+ // --- END Hide options when clicking outside ---
888
+
889
+
890
+ // Function to send message (MODIFIED to include files)
891
+ async function sendMessage() {
892
+ const text = userInput.value.trim();
893
+ if (!text && attachedFiles.length === 0) return; // Don't send empty message with no files
894
+
895
+ if (!welcomeMessage.classList.contains('d-none')) {
896
+ welcomeMessage.classList.add('d-none');
897
+ }
898
+
899
+ if (initialMessage.classList.contains('d-none')) {
900
+ initialMessage.classList.remove('d-none');
901
+ }
902
+
903
+ // Display user message. If files are attached, mention them.
904
+ let userMessageContent = text;
905
+ if (attachedFiles.length > 0) {
906
+ const fileNames = attachedFiles.map(f => f.name).join(', ');
907
+ userMessageContent += ` (Attached: ${fileNames})`;
908
+ }
909
+ addMessage(userMessageContent, 'user');
910
+
911
+ userInput.value = '';
912
+ // Clear attached files and chips
913
+ attachedFiles = [];
914
+ attachedFilePreviewContainer.innerHTML = '';
915
+ // Trigger autoGrow to reset padding and alignment
916
+ autoGrowTextarea();
917
+ userInput.dispatchEvent(new Event('input', { bubbles: true }));
918
+
919
+
920
+ typingIndicator.classList.remove('d-none');
921
+ scrollToBottom();
922
+
923
+ // --- MODIFIED: Create FormData for sending text and files ---
924
+ const formData = new FormData();
925
+ formData.append('message', text);
926
+ formData.append('api_key', 'gakr-ai-2025-secret'); // ← ADD THIS LINE
927
+ attachedFiles.forEach((file, index) => {
928
+ formData.append(`file${index}`, file);
929
+ });
930
+
931
+ try {
932
+ const response = await fetch('/api/chat', {
933
+ method: 'POST',
934
+ // Do NOT set 'Content-Type': 'application/json' for FormData.
935
+ // The browser sets the correct 'Content-Type: multipart/form-data' automatically.
936
+ body: formData
937
+ });
938
+
939
+ if (!response.ok) {
940
+ console.error('HTTP error', response.status);
941
+ const errorText = await response.text();
942
+ throw new Error(`HTTP error ${response.status}: ${errorText}`);
943
+ }
944
+
945
+ const data = await response.json();
946
+ console.log("AI response received:", data);
947
+
948
+ typingIndicator.classList.add('d-none');
949
+
950
+ let responseText = data;
951
+ if (typeof data === 'object' && data !== null) {
952
+ responseText = data.response;
953
+ if (responseText === undefined) {
954
+ try {
955
+ responseText = JSON.stringify(data, null, 2);
956
+ } catch (e) {
957
+ responseText = data.toString();
958
+ }
959
+ }
960
+ } else {
961
+ responseText = String(data);
962
+ }
963
+
964
+ addMessage(responseText, 'ai');
965
+ messageCount++;
966
+
967
+ if (messageCount === 5 && !loginPrompt.classList.contains('show')) {
968
+ loginPrompt.classList.add('show');
969
+ }
970
+ } catch (error) {
971
+ console.error('Fetch Error:', error);
972
+ typingIndicator.classList.add('d-none');
973
+ if (chatContainer) {
974
+ addMessage('Sorry, I encountered an error sending your message or files. Please try again.', 'ai');
975
+ }
976
+ } finally {
977
+ if (typingIndicator) {
978
+ typingIndicator.classList.add('d-none');
979
+ }
980
+ scrollToBottom();
981
+ }
982
+ }
983
+
984
+ // Function to add message to chat (keep existing)
985
+ function addMessage(text, type) {
986
+ const messageDiv = document.createElement('div');
987
+ messageDiv.className = `gemini-message gemini-message-${type}`;
988
+
989
+ const headerDiv = document.createElement('div');
990
+ headerDiv.className = 'gemini-message-header';
991
+
992
+ const avatarDiv = document.createElement('div');
993
+ avatarDiv.className = 'gemini-message-avatar';
994
+
995
+ const avatarIcon = document.createElement('i');
996
+ avatarIcon.className = type === 'user' ? 'fas fa-user' : 'fas fa-robot';
997
+
998
+ const nameSpan = document.createElement('span');
999
+ nameSpan.textContent = type === 'user' ? 'You' : 'GAKR AI';
1000
+
1001
+ const contentDiv = document.createElement('div');
1002
+ contentDiv.className = 'gemini-message-content';
1003
+ contentDiv.textContent = text; // Use textContent to prevent XSS if text comes from API
1004
+
1005
+ avatarDiv.appendChild(avatarIcon);
1006
+ headerDiv.appendChild(avatarDiv);
1007
+ headerDiv.appendChild(nameSpan);
1008
+
1009
+ messageDiv.appendChild(headerDiv);
1010
+ messageDiv.appendChild(contentDiv);
1011
+
1012
+ chatContainer.appendChild(messageDiv);
1013
+
1014
+ scrollToBottom();
1015
+ }
1016
+
1017
+ // Function to scroll chat to bottom (keep existing)
1018
+ function scrollToBottom() {
1019
+ setTimeout(() => {
1020
+ if (chatContainer) {
1021
+ chatContainer.scrollTop = chatContainer.scrollHeight;
1022
+ }
1023
+ }, 0);
1024
+ }
1025
+
1026
+ // Initialize based on URL query params (keep existing)
1027
+ const urlParams = new URLSearchParams(window.location.search);
1028
+ const initialQuery = urlParams.get('q');
1029
+
1030
+ if (initialQuery) {
1031
+ userInput.value = initialQuery;
1032
+ userInput.dispatchEvent(new Event('input', { bubbles: true }));
1033
+
1034
+ setTimeout(function() {
1035
+ if (submitButton && !submitButton.classList.contains('disabled')) {
1036
+ submitButton.click();
1037
+ }
1038
+ }, 100);
1039
+ } else {
1040
+ if (userInput) {
1041
+ // Initial check for submit button state
1042
+ if (userInput.value.trim().length === 0 && attachedFiles.length === 0) {
1043
+ if (submitButton) submitButton.classList.add('disabled');
1044
+ } else {
1045
+ if (submitButton) submitButton.classList.remove('disabled');
1046
+ }
1047
+ // Trigger autoGrowTextarea immediately on load for correct initial height
1048
+ autoGrowTextarea();
1049
+ }
1050
+ }
1051
+ });
1052
+ </script>
1053
+ </body>
1054
+ </html>