@djangocfg/layouts 2.1.109 → 2.1.111

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/package.json +16 -14
  2. package/src/components/errors/ErrorBoundary.tsx +12 -6
  3. package/src/components/errors/ErrorLayout.tsx +19 -9
  4. package/src/components/errors/errorConfig.ts +28 -22
  5. package/src/layouts/AuthLayout/AuthLayout.tsx +92 -20
  6. package/src/layouts/AuthLayout/components/index.ts +11 -7
  7. package/src/layouts/AuthLayout/components/oauth/index.ts +0 -1
  8. package/src/layouts/AuthLayout/components/shared/AuthButton.tsx +35 -0
  9. package/src/layouts/AuthLayout/components/shared/AuthContainer.tsx +56 -0
  10. package/src/layouts/AuthLayout/components/shared/AuthDivider.tsx +22 -0
  11. package/src/layouts/AuthLayout/components/shared/AuthError.tsx +26 -0
  12. package/src/layouts/AuthLayout/components/shared/AuthFooter.tsx +47 -0
  13. package/src/layouts/AuthLayout/components/shared/AuthHeader.tsx +53 -0
  14. package/src/layouts/AuthLayout/components/shared/AuthLink.tsx +41 -0
  15. package/src/layouts/AuthLayout/components/shared/AuthOTPInput.tsx +42 -0
  16. package/src/layouts/AuthLayout/components/shared/ChannelToggle.tsx +48 -0
  17. package/src/layouts/AuthLayout/components/shared/TermsCheckbox.tsx +57 -0
  18. package/src/layouts/AuthLayout/components/shared/index.ts +21 -0
  19. package/src/layouts/AuthLayout/components/steps/IdentifierStep.tsx +171 -0
  20. package/src/layouts/AuthLayout/components/steps/OTPStep.tsx +114 -0
  21. package/src/layouts/AuthLayout/components/steps/SetupStep/SetupComplete.tsx +70 -0
  22. package/src/layouts/AuthLayout/components/steps/SetupStep/SetupLoading.tsx +24 -0
  23. package/src/layouts/AuthLayout/components/steps/SetupStep/SetupQRCode.tsx +125 -0
  24. package/src/layouts/AuthLayout/components/steps/SetupStep/index.tsx +91 -0
  25. package/src/layouts/AuthLayout/components/steps/TwoFactorStep.tsx +92 -0
  26. package/src/layouts/AuthLayout/components/steps/index.ts +6 -0
  27. package/src/layouts/AuthLayout/constants.ts +24 -0
  28. package/src/layouts/AuthLayout/content.ts +78 -0
  29. package/src/layouts/AuthLayout/hooks/index.ts +1 -0
  30. package/src/layouts/AuthLayout/hooks/useCopyToClipboard.ts +37 -0
  31. package/src/layouts/AuthLayout/index.ts +9 -5
  32. package/src/layouts/AuthLayout/styles/auth.css +578 -0
  33. package/src/layouts/ProfileLayout/ProfileLayout.tsx +130 -58
  34. package/src/layouts/ProfileLayout/components/TwoFactorSection.tsx +2 -2
  35. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +12 -4
  36. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +6 -2
  37. package/src/layouts/_components/UserMenu.tsx +14 -6
  38. package/src/snippets/AuthDialog/AuthDialog.tsx +15 -6
  39. package/src/snippets/Breadcrumbs.tsx +19 -8
  40. package/src/snippets/McpChat/components/ChatPanel.tsx +16 -6
  41. package/src/snippets/McpChat/components/ChatSidebar.tsx +20 -8
  42. package/src/snippets/PWAInstall/components/A2HSHint.tsx +23 -10
  43. package/src/snippets/PWAInstall/components/DesktopGuide.tsx +44 -32
  44. package/src/snippets/PWAInstall/components/IOSGuideDrawer.tsx +34 -25
  45. package/src/snippets/PWAInstall/components/IOSGuideModal.tsx +34 -25
  46. package/src/snippets/PushNotifications/components/PushPrompt.tsx +16 -6
  47. package/src/layouts/AuthLayout/components/AuthHelp.tsx +0 -114
  48. package/src/layouts/AuthLayout/components/AuthSuccess.tsx +0 -101
  49. package/src/layouts/AuthLayout/components/IdentifierForm.tsx +0 -322
  50. package/src/layouts/AuthLayout/components/OTPForm.tsx +0 -174
  51. package/src/layouts/AuthLayout/components/TwoFactorForm.tsx +0 -140
  52. package/src/layouts/AuthLayout/components/TwoFactorSetup.tsx +0 -286
  53. package/src/layouts/AuthLayout/components/oauth/OAuthProviders.tsx +0 -56
@@ -0,0 +1,578 @@
1
+ /**
2
+ * Auth Layout Styles
3
+ *
4
+ * Minimal auth-specific styles.
5
+ * Uses design system variables from @djangocfg/ui-core.
6
+ */
7
+
8
+ /* ===== SPRING EASINGS ===== */
9
+
10
+ :root {
11
+ --spring-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
12
+ --spring-smooth: cubic-bezier(0.16, 1, 0.3, 1);
13
+ --spring-snappy: cubic-bezier(0.2, 0, 0, 1);
14
+ }
15
+
16
+ /* ===== LAYOUT ===== */
17
+
18
+ .auth-layout {
19
+ min-height: 100vh;
20
+ min-height: 100dvh;
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ justify-content: center;
25
+ padding: 1.5rem;
26
+ background: hsl(var(--background));
27
+ }
28
+
29
+ /* ===== CONTAINER ===== */
30
+
31
+ .auth-container {
32
+ width: 100%;
33
+ max-width: 400px;
34
+ display: flex;
35
+ flex-direction: column;
36
+ gap: 2rem;
37
+ padding: 2rem;
38
+ background: hsl(var(--card));
39
+ border: 1px solid hsl(var(--border));
40
+ border-radius: 1rem;
41
+ }
42
+
43
+ .auth-container[data-entering="true"] {
44
+ animation: authFadeIn 0.4s var(--spring-smooth) forwards;
45
+ }
46
+
47
+ @keyframes authFadeIn {
48
+ from {
49
+ opacity: 0;
50
+ transform: translateY(20px);
51
+ }
52
+ to {
53
+ opacity: 1;
54
+ transform: translateY(0);
55
+ }
56
+ }
57
+
58
+ /* ===== HEADER ===== */
59
+
60
+ .auth-header {
61
+ text-align: center;
62
+ display: flex;
63
+ flex-direction: column;
64
+ align-items: center;
65
+ gap: 0.5rem;
66
+ }
67
+
68
+ .auth-logo {
69
+ width: 64px;
70
+ height: 64px;
71
+ margin-bottom: 0.5rem;
72
+ object-fit: contain;
73
+ }
74
+
75
+ .auth-title {
76
+ font-size: 1.5rem;
77
+ font-weight: 600;
78
+ line-height: 1.2;
79
+ color: hsl(var(--foreground));
80
+ margin: 0;
81
+ }
82
+
83
+ .auth-subtitle {
84
+ font-size: 0.9375rem;
85
+ color: hsl(var(--muted-foreground));
86
+ margin: 0;
87
+ }
88
+
89
+ .auth-identifier {
90
+ font-weight: 500;
91
+ color: hsl(var(--foreground));
92
+ }
93
+
94
+ /* ===== FORM ===== */
95
+
96
+ .auth-form-group {
97
+ display: flex;
98
+ flex-direction: column;
99
+ gap: 1rem;
100
+ }
101
+
102
+ .auth-input {
103
+ width: 100%;
104
+ height: 3rem;
105
+ padding: 0 1rem;
106
+ font-size: 0.9375rem;
107
+ background: hsl(var(--input));
108
+ border: 1px solid hsl(var(--border));
109
+ border-radius: 0.5rem;
110
+ color: hsl(var(--foreground));
111
+ transition: border-color 0.2s, box-shadow 0.2s;
112
+ }
113
+
114
+ .auth-input:focus {
115
+ outline: none;
116
+ border-color: hsl(var(--ring));
117
+ box-shadow: 0 0 0 3px hsl(var(--ring) / 0.1);
118
+ }
119
+
120
+ .auth-input:disabled {
121
+ opacity: 0.5;
122
+ cursor: not-allowed;
123
+ }
124
+
125
+ .auth-input::placeholder {
126
+ color: hsl(var(--muted-foreground));
127
+ }
128
+
129
+ /* Phone input */
130
+ .auth-phone-input .PhoneInputInput {
131
+ height: 3rem;
132
+ padding: 0 1rem;
133
+ font-size: 0.9375rem;
134
+ background: hsl(var(--input));
135
+ border: 1px solid hsl(var(--border));
136
+ border-radius: 0.5rem;
137
+ color: hsl(var(--foreground));
138
+ }
139
+
140
+ .auth-phone-input .PhoneInputInput:focus {
141
+ outline: none;
142
+ border-color: hsl(var(--ring));
143
+ box-shadow: 0 0 0 3px hsl(var(--ring) / 0.1);
144
+ }
145
+
146
+ /* ===== BUTTONS ===== */
147
+
148
+ .auth-button {
149
+ width: 100%;
150
+ height: 3rem;
151
+ display: flex;
152
+ align-items: center;
153
+ justify-content: center;
154
+ gap: 0.5rem;
155
+ font-size: 0.9375rem;
156
+ font-weight: 500;
157
+ border-radius: 0.5rem;
158
+ border: none;
159
+ cursor: pointer;
160
+ transition: opacity 0.15s, transform 0.15s;
161
+ }
162
+
163
+ .auth-button:active:not(:disabled) {
164
+ transform: scale(0.98);
165
+ }
166
+
167
+ .auth-button:disabled {
168
+ opacity: 0.5;
169
+ cursor: not-allowed;
170
+ }
171
+
172
+ .auth-button-primary {
173
+ background: hsl(var(--primary));
174
+ color: hsl(var(--primary-foreground));
175
+ }
176
+
177
+ .auth-button-primary:hover:not(:disabled) {
178
+ opacity: 0.9;
179
+ }
180
+
181
+ .auth-button-secondary {
182
+ background: hsl(var(--secondary));
183
+ color: hsl(var(--secondary-foreground));
184
+ }
185
+
186
+ .auth-button-secondary:hover:not(:disabled) {
187
+ opacity: 0.9;
188
+ }
189
+
190
+ /* Loading state */
191
+ .auth-button-loading {
192
+ color: transparent !important;
193
+ position: relative;
194
+ }
195
+
196
+ .auth-button-loading::before {
197
+ content: "";
198
+ position: absolute;
199
+ width: 1.25rem;
200
+ height: 1.25rem;
201
+ border: 2px solid currentColor;
202
+ border-right-color: transparent;
203
+ border-radius: 50%;
204
+ animation: authSpin 0.6s linear infinite;
205
+ }
206
+
207
+ .auth-button-primary.auth-button-loading::before {
208
+ border-color: hsl(var(--primary-foreground));
209
+ border-right-color: transparent;
210
+ }
211
+
212
+ @keyframes authSpin {
213
+ to { transform: rotate(360deg); }
214
+ }
215
+
216
+ /* ===== DIVIDER ===== */
217
+
218
+ .auth-divider {
219
+ display: flex;
220
+ align-items: center;
221
+ gap: 1rem;
222
+ color: hsl(var(--muted-foreground));
223
+ font-size: 0.8125rem;
224
+ }
225
+
226
+ .auth-divider::before,
227
+ .auth-divider::after {
228
+ content: "";
229
+ flex: 1;
230
+ height: 1px;
231
+ background: hsl(var(--border));
232
+ }
233
+
234
+ /* ===== LINKS ===== */
235
+
236
+ .auth-link {
237
+ display: inline-flex;
238
+ align-items: center;
239
+ gap: 0.25rem;
240
+ font-size: 0.875rem;
241
+ color: hsl(var(--primary));
242
+ background: none;
243
+ border: none;
244
+ padding: 0;
245
+ cursor: pointer;
246
+ transition: opacity 0.15s;
247
+ }
248
+
249
+ .auth-link:hover {
250
+ opacity: 0.8;
251
+ }
252
+
253
+ .auth-link:disabled {
254
+ opacity: 0.5;
255
+ cursor: not-allowed;
256
+ }
257
+
258
+ .auth-actions {
259
+ display: flex;
260
+ justify-content: center;
261
+ gap: 1.5rem;
262
+ }
263
+
264
+ /* ===== ERROR ===== */
265
+
266
+ .auth-error {
267
+ padding: 0.75rem 1rem;
268
+ font-size: 0.875rem;
269
+ color: hsl(var(--destructive));
270
+ background: hsl(var(--destructive) / 0.1);
271
+ border: 1px solid hsl(var(--destructive) / 0.2);
272
+ border-radius: 0.5rem;
273
+ animation: authShake 0.4s ease;
274
+ }
275
+
276
+ @keyframes authShake {
277
+ 0%, 100% { transform: translateX(0); }
278
+ 20% { transform: translateX(-6px); }
279
+ 40% { transform: translateX(6px); }
280
+ 60% { transform: translateX(-4px); }
281
+ 80% { transform: translateX(4px); }
282
+ }
283
+
284
+ /* ===== FOOTER ===== */
285
+
286
+ .auth-footer {
287
+ display: flex;
288
+ justify-content: center;
289
+ gap: 0.75rem;
290
+ font-size: 0.8125rem;
291
+ color: hsl(var(--muted-foreground));
292
+ }
293
+
294
+ .auth-footer a {
295
+ color: inherit;
296
+ text-decoration: none;
297
+ }
298
+
299
+ .auth-footer a:hover {
300
+ color: hsl(var(--foreground));
301
+ }
302
+
303
+ .auth-footer-dot {
304
+ opacity: 0.3;
305
+ }
306
+
307
+ /* ===== TERMS ===== */
308
+
309
+ .auth-terms {
310
+ display: flex;
311
+ align-items: flex-start;
312
+ gap: 0.75rem;
313
+ font-size: 0.875rem;
314
+ color: hsl(var(--muted-foreground));
315
+ }
316
+
317
+ .auth-terms-checkbox {
318
+ margin-top: 2px;
319
+ flex-shrink: 0;
320
+ }
321
+
322
+ .auth-terms a {
323
+ color: hsl(var(--primary));
324
+ text-decoration: none;
325
+ }
326
+
327
+ .auth-terms a:hover {
328
+ opacity: 0.8;
329
+ }
330
+
331
+ /* ===== CHANNEL TOGGLE ===== */
332
+
333
+ .auth-channel-toggle {
334
+ display: flex;
335
+ padding: 4px;
336
+ background: hsl(var(--muted));
337
+ border-radius: 0.5rem;
338
+ gap: 4px;
339
+ }
340
+
341
+ .auth-channel-option {
342
+ flex: 1;
343
+ display: flex;
344
+ align-items: center;
345
+ justify-content: center;
346
+ gap: 0.375rem;
347
+ padding: 0.5rem 1rem;
348
+ font-size: 0.875rem;
349
+ font-weight: 500;
350
+ color: hsl(var(--muted-foreground));
351
+ background: transparent;
352
+ border: none;
353
+ border-radius: 0.375rem;
354
+ cursor: pointer;
355
+ transition: all 0.2s;
356
+ }
357
+
358
+ .auth-channel-option[data-active="true"] {
359
+ color: hsl(var(--foreground));
360
+ background: hsl(var(--card));
361
+ box-shadow: 0 1px 2px hsl(0 0% 0% / 0.05);
362
+ }
363
+
364
+ .auth-channel-option svg {
365
+ width: 1rem;
366
+ height: 1rem;
367
+ }
368
+
369
+ /* ===== OTP INPUT ===== */
370
+
371
+ .auth-otp-container {
372
+ display: flex;
373
+ justify-content: center;
374
+ }
375
+
376
+ .auth-otp-wrapper {
377
+ display: flex;
378
+ gap: 0.5rem;
379
+ }
380
+
381
+ .auth-otp-wrapper input {
382
+ width: 3rem;
383
+ height: 3.5rem;
384
+ font-size: 1.25rem;
385
+ font-weight: 500;
386
+ text-align: center;
387
+ background: hsl(var(--input));
388
+ border: 1px solid hsl(var(--border));
389
+ border-radius: 0.5rem;
390
+ color: hsl(var(--foreground));
391
+ transition: border-color 0.2s, box-shadow 0.2s;
392
+ }
393
+
394
+ .auth-otp-wrapper input:focus {
395
+ outline: none;
396
+ border-color: hsl(var(--ring));
397
+ box-shadow: 0 0 0 3px hsl(var(--ring) / 0.1);
398
+ }
399
+
400
+ .auth-otp-wrapper input:disabled {
401
+ opacity: 0.5;
402
+ }
403
+
404
+ /* ===== QR CODE ===== */
405
+
406
+ .auth-qr-container {
407
+ display: flex;
408
+ justify-content: center;
409
+ padding: 1rem 0;
410
+ }
411
+
412
+ .auth-qr {
413
+ padding: 1rem;
414
+ background: white;
415
+ border-radius: 0.5rem;
416
+ box-shadow: 0 2px 8px hsl(0 0% 0% / 0.08);
417
+ }
418
+
419
+ /* ===== SECRET CODE ===== */
420
+
421
+ .auth-secret-container {
422
+ display: flex;
423
+ flex-direction: column;
424
+ align-items: center;
425
+ gap: 0.5rem;
426
+ padding: 1rem;
427
+ }
428
+
429
+ .auth-secret {
430
+ padding: 0.5rem 1rem;
431
+ font-family: ui-monospace, monospace;
432
+ font-size: 0.8125rem;
433
+ letter-spacing: 0.05em;
434
+ background: hsl(var(--muted));
435
+ border-radius: 0.375rem;
436
+ color: hsl(var(--foreground));
437
+ word-break: break-all;
438
+ text-align: center;
439
+ }
440
+
441
+ /* ===== BACKUP CODES ===== */
442
+
443
+ .auth-backup-codes {
444
+ display: grid;
445
+ grid-template-columns: repeat(2, 1fr);
446
+ gap: 0.5rem;
447
+ padding: 1rem;
448
+ background: hsl(var(--muted) / 0.5);
449
+ border: 1px dashed hsl(var(--border));
450
+ border-radius: 0.5rem;
451
+ }
452
+
453
+ .auth-backup-code {
454
+ font-family: ui-monospace, monospace;
455
+ font-size: 0.8125rem;
456
+ text-align: center;
457
+ padding: 0.5rem;
458
+ color: hsl(var(--foreground));
459
+ }
460
+
461
+ /* ===== SUCCESS OVERLAY ===== */
462
+
463
+ .auth-success-overlay {
464
+ position: fixed;
465
+ inset: 0;
466
+ display: flex;
467
+ align-items: center;
468
+ justify-content: center;
469
+ background: hsl(var(--background));
470
+ z-index: 50;
471
+ animation: authFadeIn 0.3s ease-out;
472
+ }
473
+
474
+ .auth-success-content {
475
+ display: flex;
476
+ flex-direction: column;
477
+ align-items: center;
478
+ gap: 1.5rem;
479
+ }
480
+
481
+ .auth-success-logo {
482
+ width: 80px;
483
+ height: 80px;
484
+ object-fit: contain;
485
+ animation: authSuccessIn 0.5s var(--spring-bounce);
486
+ }
487
+
488
+ .auth-success-check {
489
+ width: 80px;
490
+ height: 80px;
491
+ display: flex;
492
+ align-items: center;
493
+ justify-content: center;
494
+ background: hsl(142 76% 36% / 0.1);
495
+ border-radius: 50%;
496
+ color: hsl(142 76% 36%);
497
+ animation: authSuccessIn 0.5s var(--spring-bounce);
498
+ }
499
+
500
+ @keyframes authSuccessIn {
501
+ from {
502
+ opacity: 0;
503
+ transform: scale(0.5);
504
+ }
505
+ to {
506
+ opacity: 1;
507
+ transform: scale(1);
508
+ }
509
+ }
510
+
511
+ .auth-success-check svg {
512
+ width: 40px;
513
+ height: 40px;
514
+ }
515
+
516
+ .auth-success-text {
517
+ font-size: 0.9375rem;
518
+ color: hsl(var(--muted-foreground));
519
+ }
520
+
521
+ /* ===== DEV NOTICE ===== */
522
+
523
+ .auth-dev-notice {
524
+ padding: 0.5rem 0.75rem;
525
+ font-size: 0.75rem;
526
+ text-align: center;
527
+ color: hsl(38 92% 40%);
528
+ background: hsl(38 92% 95%);
529
+ border-radius: 0.375rem;
530
+ border: 1px solid hsl(38 92% 80%);
531
+ }
532
+
533
+ .dark .auth-dev-notice {
534
+ color: hsl(38 92% 65%);
535
+ background: hsl(38 92% 15%);
536
+ border-color: hsl(38 92% 30%);
537
+ }
538
+
539
+ /* ===== INSTRUCTION ===== */
540
+
541
+ .auth-instruction {
542
+ font-size: 0.875rem;
543
+ color: hsl(var(--muted-foreground));
544
+ text-align: center;
545
+ margin: 0;
546
+ }
547
+
548
+ /* ===== RESPONSIVE ===== */
549
+
550
+ @media (max-width: 480px) {
551
+ .auth-layout {
552
+ padding: 1rem;
553
+ }
554
+
555
+ .auth-container {
556
+ padding: 1.5rem;
557
+ gap: 1.5rem;
558
+ }
559
+
560
+ .auth-title {
561
+ font-size: 1.25rem;
562
+ }
563
+
564
+ .auth-otp-wrapper input {
565
+ width: 2.75rem;
566
+ height: 3rem;
567
+ font-size: 1rem;
568
+ }
569
+ }
570
+
571
+ /* ===== REDUCED MOTION ===== */
572
+
573
+ @media (prefers-reduced-motion: reduce) {
574
+ *, *::before, *::after {
575
+ animation-duration: 0.01ms !important;
576
+ transition-duration: 0.01ms !important;
577
+ }
578
+ }