findEthics commited on
Commit
b4487f6
·
1 Parent(s): c658e00

Optimize UI for mobile devices with minimal design

Browse files

- Add responsive mobile navigation with icon buttons
- Implement rounded corners throughout UI (1-2rem radius)
- Remove all animations for instant, clean transitions
- Create PWA manifest and app icons for mobile experience
- Reorganize header: removed hamburger menu, simplified layout
- Change "Create Account" to "Register" for consistency
- Ensure single-row header layout across all screen sizes
- Mobile: Show icon buttons (👤 for Login, ➕ for Register)
- Desktop: Show text buttons for Login and Register
- Improve touch targets (min 48px) and spacing on mobile
- Add mobile-first responsive breakpoints
- Black & white minimal design maintained throughout

README.md CHANGED
@@ -255,7 +255,7 @@ export FLASK_ENV=development
255
 
256
  ### Production Deployment
257
 
258
- For production deployment, see [PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md) for comprehensive instructions including:
259
 
260
  - Security configuration
261
  - Database setup
@@ -311,7 +311,7 @@ export FLASK_ENV=production
311
  - Check application logs for detailed error messages
312
  - Review configuration with `python deploy.py check-prod`
313
  - Test individual components with provided test scripts
314
- - Consult [PRODUCTION_DEPLOYMENT.md](PRODUCTION_DEPLOYMENT.md) for deployment issues
315
 
316
  ## Security
317
 
 
255
 
256
  ### Production Deployment
257
 
258
+ For production deployment, see [PRODUCTION_DEPLOYMENT.md](docs/PRODUCTION_DEPLOYMENT.md) for comprehensive instructions including:
259
 
260
  - Security configuration
261
  - Database setup
 
311
  - Check application logs for detailed error messages
312
  - Review configuration with `python deploy.py check-prod`
313
  - Test individual components with provided test scripts
314
+ - Consult [PRODUCTION_DEPLOYMENT.md](docs/PRODUCTION_DEPLOYMENT.md) for deployment issues
315
 
316
  ## Security
317
 
__pycache__/config.cpython-313.pyc CHANGED
Binary files a/__pycache__/config.cpython-313.pyc and b/__pycache__/config.cpython-313.pyc differ
 
DEPLOYMENT.md → docs/DEPLOYMENT.md RENAMED
File without changes
HUGGINGFACE_DEPLOYMENT_CHECKLIST.md → docs/HUGGINGFACE_DEPLOYMENT_CHECKLIST.md RENAMED
File without changes
INSTALLATION.md → docs/INSTALLATION.md RENAMED
File without changes
PRODUCTION_DEPLOYMENT.md → docs/PRODUCTION_DEPLOYMENT.md RENAMED
@@ -104,14 +104,15 @@ This guide covers deploying the Chatty application in a production environment w
104
  ### Docker Deployment
105
 
106
  Create `Dockerfile`:
 
107
  ```dockerfile
108
  FROM python:3.9-slim
109
 
110
  WORKDIR /app
111
- COPY requirements.txt .
112
  RUN pip install -r requirements.txt
113
 
114
- COPY . .
115
 
116
  ENV FLASK_ENV=production
117
  EXPOSE 7860
 
104
  ### Docker Deployment
105
 
106
  Create `Dockerfile`:
107
+
108
  ```dockerfile
109
  FROM python:3.9-slim
110
 
111
  WORKDIR /app
112
+ COPY ../requirements.txt .
113
  RUN pip install -r requirements.txt
114
 
115
+ COPY .. .
116
 
117
  ENV FLASK_ENV=production
118
  EXPOSE 7860
TRANSFORMATION_SUMMARY.md → docs/TRANSFORMATION_SUMMARY.md RENAMED
File without changes
instructions.md → docs/instructions.md RENAMED
File without changes
task_list.md → docs/task_list.md RENAMED
File without changes
static/css/auth.css CHANGED
@@ -37,15 +37,32 @@
37
  .nav-button {
38
  background-color: transparent;
39
  color: white;
40
- border: 1px solid white;
41
  padding: 0.375rem 0.75rem;
42
- border-radius: 0.5rem;
43
  text-decoration: none;
44
  font-size: 0.8rem;
45
- transition: all 0.2s ease;
46
  cursor: pointer;
47
  font-family: inherit;
48
  white-space: nowrap;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
50
 
51
  .nav-button:hover {
@@ -60,7 +77,7 @@
60
 
61
  .logout-button {
62
  background-color: transparent;
63
- border: 1px solid white;
64
  }
65
 
66
  /* Desktop header navigation */
@@ -88,11 +105,10 @@
88
 
89
  .flash-message {
90
  padding: 0.75rem 1rem;
91
- border-radius: 0.5rem;
92
  margin-bottom: 0.5rem;
93
  border: 2px solid;
94
  font-size: 0.9rem;
95
- animation: fadeIn 0.3s ease-in;
96
  }
97
 
98
  .flash-message:last-child {
@@ -144,9 +160,8 @@
144
  max-width: 400px;
145
  background-color: white;
146
  border: 2px solid black;
147
- border-radius: 1rem;
148
  padding: 2rem;
149
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
150
  }
151
 
152
  .auth-form h2 {
@@ -173,11 +188,10 @@
173
  width: 100%;
174
  padding: 0.75rem 1rem;
175
  border: 2px solid black;
176
- border-radius: 0.75rem;
177
  font-size: 1rem;
178
  background-color: white;
179
  color: black;
180
- transition: border-color 0.2s ease;
181
  font-family: inherit;
182
  -webkit-appearance: none;
183
  appearance: none;
@@ -210,11 +224,10 @@
210
  background-color: black;
211
  color: white;
212
  border: 2px solid black;
213
- border-radius: 0.75rem;
214
  font-size: 1rem;
215
  font-weight: 500;
216
  cursor: pointer;
217
- transition: all 0.2s ease;
218
  margin-bottom: 1rem;
219
  font-family: inherit;
220
  }
@@ -222,19 +235,15 @@
222
  .auth-button:hover {
223
  background-color: white;
224
  color: black;
225
- transform: translateY(-1px);
226
  }
227
 
228
- .auth-button:active {
229
- transform: translateY(0);
230
- }
231
 
232
  .auth-button:disabled {
233
  background-color: white;
234
  color: black;
235
  opacity: 0.5;
236
  cursor: not-allowed;
237
- transform: none;
238
  }
239
 
240
  .auth-links {
@@ -246,7 +255,6 @@
246
  color: black;
247
  text-decoration: underline;
248
  font-size: 0.9rem;
249
- transition: opacity 0.2s ease;
250
  }
251
 
252
  .auth-links a:hover {
@@ -289,15 +297,6 @@
289
 
290
  /* Mobile optimizations */
291
  @media (max-width: 768px) {
292
- .header-nav {
293
- gap: 0.5rem;
294
- }
295
-
296
- .nav-button {
297
- padding: 0.25rem 0.5rem;
298
- font-size: 0.75rem;
299
- }
300
-
301
  .user-info {
302
  font-size: 0.7rem;
303
  margin-right: 0.25rem;
@@ -376,41 +375,11 @@
376
  }
377
 
378
  /* Spinner for form buttons */
379
- .spinner {
380
- width: 16px;
381
- height: 16px;
382
- border: 2px solid transparent;
383
- border-top: 2px solid currentColor;
384
- border-radius: 50%;
385
- animation: spin 1s linear infinite;
386
- margin-left: 0.5rem;
387
- }
388
-
389
- @keyframes spin {
390
- 0% {
391
- transform: rotate(0deg);
392
- }
393
- 100% {
394
- transform: rotate(360deg);
395
- }
396
- }
397
 
398
- /* Reduced motion support */
399
- @media (prefers-reduced-motion: reduce) {
400
- .nav-button,
401
- .auth-button,
402
- .logo-link {
403
- transition: none;
404
- }
405
 
406
- .flash-message {
407
- animation: none;
408
- }
409
-
410
- .spinner {
411
- animation: none;
412
- }
413
- }/*
414
  Error pages */
415
  .error-container {
416
  flex: 1;
@@ -461,12 +430,11 @@
461
  background-color: black;
462
  color: white;
463
  border: 2px solid black;
464
- border-radius: 0.75rem;
465
  text-decoration: none;
466
  font-size: 1rem;
467
  font-weight: 500;
468
  cursor: pointer;
469
- transition: all 0.2s ease;
470
  font-family: inherit;
471
  display: inline-block;
472
  }
@@ -474,7 +442,6 @@
474
  .error-button:hover {
475
  background-color: white;
476
  color: black;
477
- transform: translateY(-1px);
478
  }
479
 
480
  .error-button.secondary {
 
37
  .nav-button {
38
  background-color: transparent;
39
  color: white;
40
+ border: 2px solid white;
41
  padding: 0.375rem 0.75rem;
42
+ border-radius: 1rem;
43
  text-decoration: none;
44
  font-size: 0.8rem;
 
45
  cursor: pointer;
46
  font-family: inherit;
47
  white-space: nowrap;
48
+ display: inline-flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ }
52
+
53
+ /* Icon styles for mobile */
54
+ @media (max-width: 768px) {
55
+ .nav-button {
56
+ padding: 0.25rem 0.4rem;
57
+ min-width: 32px;
58
+ min-height: 32px;
59
+ font-size: 1rem;
60
+ }
61
+
62
+ .nav-button .mobile-only {
63
+ line-height: 1;
64
+ display: inline-block;
65
+ }
66
  }
67
 
68
  .nav-button:hover {
 
77
 
78
  .logout-button {
79
  background-color: transparent;
80
+ border: 2px solid white;
81
  }
82
 
83
  /* Desktop header navigation */
 
105
 
106
  .flash-message {
107
  padding: 0.75rem 1rem;
108
+ border-radius: 1rem;
109
  margin-bottom: 0.5rem;
110
  border: 2px solid;
111
  font-size: 0.9rem;
 
112
  }
113
 
114
  .flash-message:last-child {
 
160
  max-width: 400px;
161
  background-color: white;
162
  border: 2px solid black;
163
+ border-radius: 1.5rem;
164
  padding: 2rem;
 
165
  }
166
 
167
  .auth-form h2 {
 
188
  width: 100%;
189
  padding: 0.75rem 1rem;
190
  border: 2px solid black;
191
+ border-radius: 1.5rem;
192
  font-size: 1rem;
193
  background-color: white;
194
  color: black;
 
195
  font-family: inherit;
196
  -webkit-appearance: none;
197
  appearance: none;
 
224
  background-color: black;
225
  color: white;
226
  border: 2px solid black;
227
+ border-radius: 2rem;
228
  font-size: 1rem;
229
  font-weight: 500;
230
  cursor: pointer;
 
231
  margin-bottom: 1rem;
232
  font-family: inherit;
233
  }
 
235
  .auth-button:hover {
236
  background-color: white;
237
  color: black;
 
238
  }
239
 
240
+ /* Active state removed for minimal design */
 
 
241
 
242
  .auth-button:disabled {
243
  background-color: white;
244
  color: black;
245
  opacity: 0.5;
246
  cursor: not-allowed;
 
247
  }
248
 
249
  .auth-links {
 
255
  color: black;
256
  text-decoration: underline;
257
  font-size: 0.9rem;
 
258
  }
259
 
260
  .auth-links a:hover {
 
297
 
298
  /* Mobile optimizations */
299
  @media (max-width: 768px) {
 
 
 
 
 
 
 
 
 
300
  .user-info {
301
  font-size: 0.7rem;
302
  margin-right: 0.25rem;
 
375
  }
376
 
377
  /* Spinner for form buttons */
378
+ /* Spinner removed - using text instead */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
 
380
+ /* Spin animation removed for minimal design */
 
 
 
 
 
 
381
 
382
+ /* Reduced motion support - animations already removed *//*
 
 
 
 
 
 
 
383
  Error pages */
384
  .error-container {
385
  flex: 1;
 
430
  background-color: black;
431
  color: white;
432
  border: 2px solid black;
433
+ border-radius: 2rem;
434
  text-decoration: none;
435
  font-size: 1rem;
436
  font-weight: 500;
437
  cursor: pointer;
 
438
  font-family: inherit;
439
  display: inline-block;
440
  }
 
442
  .error-button:hover {
443
  background-color: white;
444
  color: black;
 
445
  }
446
 
447
  .error-button.secondary {
static/css/style.css CHANGED
@@ -55,21 +55,58 @@ body {
55
  flex-shrink: 0;
56
  position: relative;
57
  z-index: 10;
 
58
  }
59
 
 
 
60
  .header-content {
61
  max-width: 100%;
 
 
 
 
 
 
62
  }
63
 
64
- .header h1 {
 
 
 
 
 
 
65
  font-size: 1.25rem;
66
- margin-bottom: 0.125rem;
67
  font-weight: 600;
68
  }
69
 
70
- .header p {
71
- opacity: 0.9;
72
- font-size: 0.8rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
74
 
75
  /* Desktop header styles */
@@ -78,13 +115,8 @@ body {
78
  padding: 1rem 2rem;
79
  }
80
 
81
- .header h1 {
82
  font-size: 2rem;
83
- margin-bottom: 0.25rem;
84
- }
85
-
86
- .header p {
87
- font-size: 0.9rem;
88
  }
89
  }
90
 
@@ -122,7 +154,6 @@ body {
122
  margin-bottom: 0.75rem;
123
  display: flex;
124
  align-items: flex-start;
125
- animation: fadeIn 0.3s ease-in;
126
  }
127
 
128
  .message.user {
@@ -135,8 +166,8 @@ body {
135
 
136
  .message-content {
137
  max-width: 85%;
138
- padding: 0.625rem 0.875rem;
139
- border-radius: 1rem;
140
  word-wrap: break-word;
141
  word-break: break-word;
142
  line-height: 1.4;
@@ -146,27 +177,17 @@ body {
146
  .message.user .message-content {
147
  background-color: black;
148
  color: white;
149
- border-bottom-right-radius: 0.25rem;
150
  }
151
 
152
  .message.assistant .message-content {
153
  background-color: white;
154
  color: black;
155
  border: 2px solid black;
156
- border-bottom-left-radius: 0.25rem;
157
  }
158
 
159
- @keyframes fadeIn {
160
- from {
161
- opacity: 0;
162
- transform: translateY(10px);
163
- }
164
-
165
- to {
166
- opacity: 1;
167
- transform: translateY(0);
168
- }
169
- }
170
 
171
  /* Desktop message styles */
172
  @media (min-width: 769px) {
@@ -210,13 +231,14 @@ body {
210
  #messageInput {
211
  flex: 1;
212
  padding: 0.75rem 1rem;
213
- border: 1px solid black;
 
214
  font-size: 1rem;
215
  outline: none;
216
  background-color: white;
217
  color: black;
218
  resize: none;
219
- min-height: 44px;
220
  /* Minimum touch target size */
221
  max-height: 120px;
222
  line-height: 1.4;
@@ -239,13 +261,14 @@ body {
239
  padding: 0.75rem 1.25rem;
240
  background-color: black;
241
  color: white;
242
- border: 1px solid black;
 
243
  font-size: 0.9rem;
244
  cursor: pointer;
245
  white-space: nowrap;
246
- min-height: 44px;
247
  /* Minimum touch target size */
248
- min-width: 44px;
249
  display: flex;
250
  align-items: center;
251
  justify-content: center;
@@ -367,33 +390,19 @@ body {
367
  transform: translateX(-50%);
368
  background-color: black;
369
  color: white;
370
- border: 1px solid black;
371
- padding: 0.75rem 1.25rem;
 
372
  display: flex;
373
  align-items: center;
374
- gap: 0.5rem;
375
  z-index: 1000;
376
  font-size: 0.9rem;
377
  }
378
 
379
- .spinner {
380
- width: 16px;
381
- height: 16px;
382
- border: 2px solid transparent;
383
- border-top: 2px solid white;
384
- border-radius: 50%;
385
- animation: spin 1s linear infinite;
386
- }
387
 
388
- @keyframes spin {
389
- 0% {
390
- transform: rotate(0deg);
391
- }
392
-
393
- 100% {
394
- transform: rotate(360deg);
395
- }
396
- }
397
 
398
  /* Desktop loading indicator */
399
  @media (min-width: 769px) {
@@ -409,11 +418,10 @@ body {
409
  background-color: white;
410
  color: black;
411
  padding: 0.75rem 1rem;
412
- border-radius: 0.75rem;
413
  border: 2px solid black;
414
  margin-bottom: 0.75rem;
415
  font-size: 0.9rem;
416
- animation: fadeIn 0.3s ease-in;
417
  }
418
 
419
  /* History loading */
@@ -424,7 +432,6 @@ body {
424
  padding: 2rem 1rem;
425
  color: black;
426
  font-size: 0.9rem;
427
- animation: fadeIn 0.3s ease-in;
428
  }
429
 
430
  .loading-text {
@@ -433,15 +440,7 @@ body {
433
  gap: 0.5rem;
434
  }
435
 
436
- .loading-text::before {
437
- content: '';
438
- width: 16px;
439
- height: 16px;
440
- border: 2px solid transparent;
441
- border-top: 2px solid black;
442
- border-radius: 50%;
443
- animation: spin 1s linear infinite;
444
- }
445
 
446
  /* History error */
447
  .history-error {
@@ -450,14 +449,13 @@ body {
450
  align-items: center;
451
  padding: 1rem;
452
  margin-bottom: 0.75rem;
453
- animation: fadeIn 0.3s ease-in;
454
  }
455
 
456
  .error-text {
457
  background-color: white;
458
  color: black;
459
  padding: 0.75rem 1rem;
460
- border-radius: 0.75rem;
461
  border: 2px solid black;
462
  font-size: 0.9rem;
463
  text-align: center;
@@ -484,6 +482,67 @@ body {
484
 
485
  /* Mobile-specific optimizations */
486
  @media (max-width: 768px) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
 
488
  /* Prevent zoom on input focus */
489
  input,
@@ -492,11 +551,6 @@ body {
492
  font-size: 16px !important;
493
  }
494
 
495
- /* Optimize for mobile keyboards */
496
- .chat-input-container {
497
- transition: padding-bottom 0.3s ease;
498
- }
499
-
500
  /* Handle virtual keyboard */
501
  @supports (height: 100dvh) {
502
  .container {
@@ -505,6 +559,31 @@ body {
505
  }
506
  }
507
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
508
  /* Tablet styles */
509
  @media (min-width: 769px) and (max-width: 1024px) {
510
  .container {
@@ -641,7 +720,8 @@ uch and interaction improvements */
641
  background: black;
642
  color: white;
643
  text-decoration: none;
644
- border: 1px solid black;
 
645
  font-weight: normal;
646
  text-transform: uppercase;
647
  letter-spacing: 1px;
@@ -682,7 +762,8 @@ uch and interaction improvements */
682
  .session-expiry-warning button {
683
  background: white;
684
  color: black;
685
- border: 1px solid white;
 
686
  padding: 0.5rem 1rem;
687
  margin: 0 0.5rem;
688
  cursor: pointer;
@@ -697,7 +778,8 @@ uch and interaction improvements */
697
  .message.system .message-content {
698
  background: white;
699
  color: black;
700
- border: 1px solid black;
 
701
  font-style: normal;
702
  }
703
 
 
55
  flex-shrink: 0;
56
  position: relative;
57
  z-index: 10;
58
+ min-height: 50px; /* Ensure consistent height */
59
  }
60
 
61
+ /* Removed hamburger menu and mobile navigation drawer - not needed */
62
+
63
  .header-content {
64
  max-width: 100%;
65
+ display: flex;
66
+ align-items: center;
67
+ justify-content: space-between;
68
+ gap: 0.5rem;
69
+ height: 100%;
70
+ white-space: nowrap;
71
  }
72
 
73
+ /* Header title */
74
+ .header-title {
75
+ flex: 0 0 auto;
76
+ text-align: left;
77
+ }
78
+
79
+ .header-title h1 {
80
  font-size: 1.25rem;
81
+ margin: 0;
82
  font-weight: 600;
83
  }
84
 
85
+ /* Header navigation */
86
+ .header-nav {
87
+ display: flex;
88
+ align-items: center;
89
+ gap: 0.25rem;
90
+ flex-shrink: 0;
91
+ }
92
+
93
+ /* Mobile/Desktop visibility helpers */
94
+ .desktop-only {
95
+ display: inline;
96
+ }
97
+
98
+ .mobile-only {
99
+ display: none;
100
+ }
101
+
102
+ @media (max-width: 768px) {
103
+ .desktop-only {
104
+ display: none;
105
+ }
106
+
107
+ .mobile-only {
108
+ display: inline;
109
+ }
110
  }
111
 
112
  /* Desktop header styles */
 
115
  padding: 1rem 2rem;
116
  }
117
 
118
+ .header-title h1 {
119
  font-size: 2rem;
 
 
 
 
 
120
  }
121
  }
122
 
 
154
  margin-bottom: 0.75rem;
155
  display: flex;
156
  align-items: flex-start;
 
157
  }
158
 
159
  .message.user {
 
166
 
167
  .message-content {
168
  max-width: 85%;
169
+ padding: 0.75rem 1rem;
170
+ border-radius: 1.5rem;
171
  word-wrap: break-word;
172
  word-break: break-word;
173
  line-height: 1.4;
 
177
  .message.user .message-content {
178
  background-color: black;
179
  color: white;
180
+ border-bottom-right-radius: 0.5rem;
181
  }
182
 
183
  .message.assistant .message-content {
184
  background-color: white;
185
  color: black;
186
  border: 2px solid black;
187
+ border-bottom-left-radius: 0.5rem;
188
  }
189
 
190
+ /* Animations removed for minimal design */
 
 
 
 
 
 
 
 
 
 
191
 
192
  /* Desktop message styles */
193
  @media (min-width: 769px) {
 
231
  #messageInput {
232
  flex: 1;
233
  padding: 0.75rem 1rem;
234
+ border: 2px solid black;
235
+ border-radius: 1.5rem;
236
  font-size: 1rem;
237
  outline: none;
238
  background-color: white;
239
  color: black;
240
  resize: none;
241
+ min-height: 48px;
242
  /* Minimum touch target size */
243
  max-height: 120px;
244
  line-height: 1.4;
 
261
  padding: 0.75rem 1.25rem;
262
  background-color: black;
263
  color: white;
264
+ border: 2px solid black;
265
+ border-radius: 2rem;
266
  font-size: 0.9rem;
267
  cursor: pointer;
268
  white-space: nowrap;
269
+ min-height: 48px;
270
  /* Minimum touch target size */
271
+ min-width: 48px;
272
  display: flex;
273
  align-items: center;
274
  justify-content: center;
 
390
  transform: translateX(-50%);
391
  background-color: black;
392
  color: white;
393
+ border: 2px solid black;
394
+ border-radius: 2rem;
395
+ padding: 0.75rem 1.5rem;
396
  display: flex;
397
  align-items: center;
398
+ justify-content: center;
399
  z-index: 1000;
400
  font-size: 0.9rem;
401
  }
402
 
403
+ /* Spinner removed - using text instead */
 
 
 
 
 
 
 
404
 
405
+ /* Spin animation removed for minimal design */
 
 
 
 
 
 
 
 
406
 
407
  /* Desktop loading indicator */
408
  @media (min-width: 769px) {
 
418
  background-color: white;
419
  color: black;
420
  padding: 0.75rem 1rem;
421
+ border-radius: 1rem;
422
  border: 2px solid black;
423
  margin-bottom: 0.75rem;
424
  font-size: 0.9rem;
 
425
  }
426
 
427
  /* History loading */
 
432
  padding: 2rem 1rem;
433
  color: black;
434
  font-size: 0.9rem;
 
435
  }
436
 
437
  .loading-text {
 
440
  gap: 0.5rem;
441
  }
442
 
443
+ /* Loading spinner removed */
 
 
 
 
 
 
 
 
444
 
445
  /* History error */
446
  .history-error {
 
449
  align-items: center;
450
  padding: 1rem;
451
  margin-bottom: 0.75rem;
 
452
  }
453
 
454
  .error-text {
455
  background-color: white;
456
  color: black;
457
  padding: 0.75rem 1rem;
458
+ border-radius: 1rem;
459
  border: 2px solid black;
460
  font-size: 0.9rem;
461
  text-align: center;
 
482
 
483
  /* Mobile-specific optimizations */
484
  @media (max-width: 768px) {
485
+ /* Header adjustments */
486
+ .header {
487
+ padding: 0.5rem 0.75rem;
488
+ }
489
+
490
+ .header-title h1 {
491
+ font-size: 1rem;
492
+ }
493
+
494
+ .header-content {
495
+ gap: 0.5rem;
496
+ flex-wrap: nowrap; /* Ensure no wrapping */
497
+ }
498
+
499
+ .header-nav {
500
+ gap: 0.25rem;
501
+ }
502
+
503
+ /* Chat messages mobile */
504
+ .chat-messages {
505
+ padding: 0.5rem;
506
+ }
507
+
508
+ .message {
509
+ margin-bottom: 0.5rem;
510
+ }
511
+
512
+ .message-content {
513
+ max-width: 90%;
514
+ padding: 0.625rem 0.875rem;
515
+ font-size: 0.95rem;
516
+ }
517
+
518
+ /* Chat input mobile */
519
+ .chat-input-container {
520
+ padding: 0.5rem;
521
+ padding-bottom: calc(0.5rem + env(safe-area-inset-bottom));
522
+ }
523
+
524
+ #messageInput {
525
+ min-height: 48px;
526
+ padding: 0.75rem 1rem;
527
+ font-size: 16px !important; /* Prevent zoom */
528
+ }
529
+
530
+ #sendButton {
531
+ min-width: 60px;
532
+ min-height: 48px;
533
+ padding: 0.75rem 1rem;
534
+ }
535
+
536
+ /* Info banner mobile */
537
+ .anonymous-info-banner {
538
+ padding: 0.5rem 0.75rem;
539
+ font-size: 0.85rem;
540
+ }
541
+
542
+ .anonymous-info-banner .message-counter {
543
+ padding: 0.25rem 0.5rem;
544
+ font-size: 0.8rem;
545
+ }
546
 
547
  /* Prevent zoom on input focus */
548
  input,
 
551
  font-size: 16px !important;
552
  }
553
 
 
 
 
 
 
554
  /* Handle virtual keyboard */
555
  @supports (height: 100dvh) {
556
  .container {
 
559
  }
560
  }
561
 
562
+ /* Small mobile devices */
563
+ @media (max-width: 480px) {
564
+ .header-title h1 {
565
+ font-size: 0.95rem;
566
+ }
567
+
568
+ .header {
569
+ padding: 0.4rem 0.5rem;
570
+ }
571
+
572
+ .message-content {
573
+ max-width: 95%;
574
+ font-size: 0.9rem;
575
+ }
576
+
577
+ #sendButton span {
578
+ display: none;
579
+ }
580
+
581
+ #sendButton::after {
582
+ content: "→";
583
+ font-size: 1.25rem;
584
+ }
585
+ }
586
+
587
  /* Tablet styles */
588
  @media (min-width: 769px) and (max-width: 1024px) {
589
  .container {
 
720
  background: black;
721
  color: white;
722
  text-decoration: none;
723
+ border: 2px solid black;
724
+ border-radius: 2rem;
725
  font-weight: normal;
726
  text-transform: uppercase;
727
  letter-spacing: 1px;
 
762
  .session-expiry-warning button {
763
  background: white;
764
  color: black;
765
+ border: 2px solid white;
766
+ border-radius: 1rem;
767
  padding: 0.5rem 1rem;
768
  margin: 0 0.5rem;
769
  cursor: pointer;
 
778
  .message.system .message-content {
779
  background: white;
780
  color: black;
781
+ border: 2px solid black;
782
+ border-radius: 1rem;
783
  font-style: normal;
784
  }
785
 
static/icons/icon-192.png ADDED
static/icons/icon-512.png ADDED
static/js/chat.js CHANGED
@@ -381,18 +381,8 @@ class ChatApp {
381
  }
382
 
383
  scrollToBottom() {
384
- // Smooth scroll to bottom with mobile optimization
385
- if (this.isMobile()) {
386
- // Use requestAnimationFrame for smoother scrolling on mobile
387
- requestAnimationFrame(() => {
388
- this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
389
- });
390
- } else {
391
- this.chatMessages.scrollTo({
392
- top: this.chatMessages.scrollHeight,
393
- behavior: 'smooth'
394
- });
395
- }
396
  }
397
 
398
  setupSessionMonitoring() {
 
381
  }
382
 
383
  scrollToBottom() {
384
+ // Instant scroll to bottom (no animations)
385
+ this.chatMessages.scrollTop = this.chatMessages.scrollHeight;
 
 
 
 
 
 
 
 
 
 
386
  }
387
 
388
  setupSessionMonitoring() {
templates/base.html CHANGED
@@ -9,31 +9,50 @@
9
  <meta name="theme-color" content="#000000">
10
  <meta name="apple-mobile-web-app-capable" content="yes">
11
  <meta name="apple-mobile-web-app-status-bar-style" content="default">
 
12
  {% block head %}{% endblock %}
13
  </head>
14
  <body>
15
  <div class="container">
16
  <header class="header">
17
  <div class="header-content">
18
- <div class="header-left">
 
19
  <h1><a href="{{ url_for('index') }}" class="logo-link">Chatty</a></h1>
20
  </div>
 
 
21
  <nav class="header-nav">
22
  {% if current_user.is_authenticated %}
23
- <span class="user-info">{{ current_user.email }}</span>
24
  <form method="POST" action="{{ url_for('logout') }}" class="logout-form">
25
  {% if config.WTF_CSRF_ENABLED %}
26
  <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
27
  {% endif %}
28
- <button type="submit" class="nav-button logout-button">Logout</button>
 
 
 
29
  </form>
30
  {% elif is_anonymous %}
31
- <span class="user-info anonymous-user">Anonymous User</span>
32
- <a href="{{ url_for('login') }}" class="nav-button">Login</a>
33
- <a href="{{ url_for('register') }}" class="nav-button">Create Account</a>
 
 
 
 
 
 
34
  {% else %}
35
- <a href="{{ url_for('login') }}" class="nav-button">Login</a>
36
- <a href="{{ url_for('register') }}" class="nav-button">Register</a>
 
 
 
 
 
 
37
  {% endif %}
38
  </nav>
39
  </div>
 
9
  <meta name="theme-color" content="#000000">
10
  <meta name="apple-mobile-web-app-capable" content="yes">
11
  <meta name="apple-mobile-web-app-status-bar-style" content="default">
12
+ <link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
13
  {% block head %}{% endblock %}
14
  </head>
15
  <body>
16
  <div class="container">
17
  <header class="header">
18
  <div class="header-content">
19
+ <!-- Title (left) -->
20
+ <div class="header-title">
21
  <h1><a href="{{ url_for('index') }}" class="logo-link">Chatty</a></h1>
22
  </div>
23
+
24
+ <!-- Navigation (right) -->
25
  <nav class="header-nav">
26
  {% if current_user.is_authenticated %}
27
+ <span class="user-info desktop-only">{{ current_user.email }}</span>
28
  <form method="POST" action="{{ url_for('logout') }}" class="logout-form">
29
  {% if config.WTF_CSRF_ENABLED %}
30
  <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
31
  {% endif %}
32
+ <button type="submit" class="nav-button logout-button">
33
+ <span class="desktop-only">Logout</span>
34
+ <span class="mobile-only">↪</span>
35
+ </button>
36
  </form>
37
  {% elif is_anonymous %}
38
+ <span class="user-info anonymous-user desktop-only">Anonymous</span>
39
+ <a href="{{ url_for('login') }}" class="nav-button">
40
+ <span class="desktop-only">Login</span>
41
+ <span class="mobile-only">👤</span>
42
+ </a>
43
+ <a href="{{ url_for('register') }}" class="nav-button">
44
+ <span class="desktop-only">Register</span>
45
+ <span class="mobile-only">➕</span>
46
+ </a>
47
  {% else %}
48
+ <a href="{{ url_for('login') }}" class="nav-button">
49
+ <span class="desktop-only">Login</span>
50
+ <span class="mobile-only">👤</span>
51
+ </a>
52
+ <a href="{{ url_for('register') }}" class="nav-button">
53
+ <span class="desktop-only">Register</span>
54
+ <span class="mobile-only">➕</span>
55
+ </a>
56
  {% endif %}
57
  </nav>
58
  </div>
templates/index.html CHANGED
@@ -42,8 +42,7 @@
42
  </div>
43
 
44
  <div class="loading-indicator" id="loadingIndicator" style="display: none;">
45
- <div class="spinner"></div>
46
- <span>Thinking...</span>
47
  </div>
48
  {% endblock %}
49
 
 
42
  </div>
43
 
44
  <div class="loading-indicator" id="loadingIndicator" style="display: none;">
45
+ <span>Loading...</span>
 
46
  </div>
47
  {% endblock %}
48
 
templates/login.html CHANGED
@@ -40,7 +40,6 @@
40
 
41
  <button type="submit" class="auth-button" id="loginButton">
42
  <span id="loginButtonText">Login</span>
43
- <div class="spinner" id="loginSpinner" style="display: none;"></div>
44
  </button>
45
 
46
  <div class="auth-links">
@@ -59,7 +58,6 @@ document.addEventListener('DOMContentLoaded', function() {
59
  const passwordInput = document.getElementById('password');
60
  const loginButton = document.getElementById('loginButton');
61
  const loginButtonText = document.getElementById('loginButtonText');
62
- const loginSpinner = document.getElementById('loginSpinner');
63
 
64
  // Email validation
65
  function validateEmail(email) {
@@ -140,8 +138,7 @@ document.addEventListener('DOMContentLoaded', function() {
140
 
141
  // Show loading state
142
  loginButton.disabled = true;
143
- loginButtonText.style.display = 'none';
144
- loginSpinner.style.display = 'inline-block';
145
 
146
  // Submit form
147
  this.submit();
@@ -154,8 +151,7 @@ document.addEventListener('DOMContentLoaded', function() {
154
  window.addEventListener('pageshow', function(event) {
155
  if (event.persisted) {
156
  loginButton.disabled = false;
157
- loginButtonText.style.display = 'inline';
158
- loginSpinner.style.display = 'none';
159
  }
160
  });
161
  });
 
40
 
41
  <button type="submit" class="auth-button" id="loginButton">
42
  <span id="loginButtonText">Login</span>
 
43
  </button>
44
 
45
  <div class="auth-links">
 
58
  const passwordInput = document.getElementById('password');
59
  const loginButton = document.getElementById('loginButton');
60
  const loginButtonText = document.getElementById('loginButtonText');
 
61
 
62
  // Email validation
63
  function validateEmail(email) {
 
138
 
139
  // Show loading state
140
  loginButton.disabled = true;
141
+ loginButtonText.textContent = 'Loading...';
 
142
 
143
  // Submit form
144
  this.submit();
 
151
  window.addEventListener('pageshow', function(event) {
152
  if (event.persisted) {
153
  loginButton.disabled = false;
154
+ loginButtonText.textContent = 'Login';
 
155
  }
156
  });
157
  });