@polderlabs/bizar 5.3.0 → 5.4.0

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 (69) hide show
  1. package/bizar-dash/dist/assets/EnvVarsSection-DqvB8ZcJ.js +4 -0
  2. package/bizar-dash/dist/assets/EnvVarsSection-DqvB8ZcJ.js.map +1 -0
  3. package/bizar-dash/dist/assets/MobileChat-DRXP2ERQ.js +1 -0
  4. package/bizar-dash/dist/assets/{MobileChat-OidrxXR9.js.map → MobileChat-DRXP2ERQ.js.map} +1 -1
  5. package/bizar-dash/dist/assets/MobileSettings-CVW9VhEo.js +1 -0
  6. package/bizar-dash/dist/assets/MobileSettings-CVW9VhEo.js.map +1 -0
  7. package/bizar-dash/dist/assets/Toast-CcZVVN4i.js +1 -0
  8. package/bizar-dash/dist/assets/Toast-CcZVVN4i.js.map +1 -0
  9. package/bizar-dash/dist/assets/{icons-Bd8piSb2.js → icons-OMEGx5KA.js} +66 -61
  10. package/bizar-dash/dist/assets/icons-OMEGx5KA.js.map +1 -0
  11. package/bizar-dash/dist/assets/main-CMAGZouj.js +16 -0
  12. package/bizar-dash/dist/assets/main-CMAGZouj.js.map +1 -0
  13. package/bizar-dash/dist/assets/{main-3G6mOhiK.css → main-O2tZVdHm.css} +1 -1
  14. package/bizar-dash/dist/assets/mobile-XN2P7YfM.js +1 -0
  15. package/bizar-dash/dist/assets/mobile-XN2P7YfM.js.map +1 -0
  16. package/bizar-dash/dist/assets/{mobile-CsZQAswA.css → mobile-layout-D6V-7WnA.css} +1 -1
  17. package/bizar-dash/dist/assets/mobile-layout-DqTxvXZp.js +2 -0
  18. package/bizar-dash/dist/assets/mobile-layout-DqTxvXZp.js.map +1 -0
  19. package/bizar-dash/dist/assets/useSlashCommands-iyoW95UB.js +2 -0
  20. package/bizar-dash/dist/assets/useSlashCommands-iyoW95UB.js.map +1 -0
  21. package/bizar-dash/dist/index.html +8 -6
  22. package/bizar-dash/dist/mobile.html +4 -4
  23. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  24. package/bizar-dash/src/server/auth.mjs +14 -1
  25. package/bizar-dash/src/server/routes/users.mjs +18 -0
  26. package/bizar-dash/src/web/MobileApp.tsx +26 -19
  27. package/bizar-dash/src/web/components/MobileBottomNav.tsx +38 -0
  28. package/bizar-dash/src/web/components/MobileDrawer.tsx +68 -0
  29. package/bizar-dash/src/web/components/MobileHeader.tsx +50 -0
  30. package/bizar-dash/src/web/components/MobileLayout.tsx +63 -0
  31. package/bizar-dash/src/web/components/TaskCard.tsx +69 -0
  32. package/bizar-dash/src/web/components/TaskCreateSheet.tsx +76 -0
  33. package/bizar-dash/src/web/main.tsx +1 -0
  34. package/bizar-dash/src/web/mobile/MobileDoctor.tsx +80 -0
  35. package/bizar-dash/src/web/mobile/MobileEval.tsx +167 -0
  36. package/bizar-dash/src/web/mobile/MobileMarketplace.tsx +106 -0
  37. package/bizar-dash/src/web/mobile/MobileMemory.tsx +108 -0
  38. package/bizar-dash/src/web/mobile/MobileOverview.tsx +213 -0
  39. package/bizar-dash/src/web/mobile/MobilePlugins.tsx +71 -0
  40. package/bizar-dash/src/web/mobile/MobileSettings.tsx +235 -180
  41. package/bizar-dash/src/web/mobile/MobileTasks.tsx +94 -0
  42. package/bizar-dash/src/web/mobile.tsx +1 -0
  43. package/bizar-dash/src/web/styles/main.css +388 -0
  44. package/bizar-dash/src/web/styles/memory.css +45 -0
  45. package/bizar-dash/src/web/styles/mobile-layout.css +231 -0
  46. package/bizar-dash/src/web/styles/mobile.css +180 -0
  47. package/bizar-dash/src/web/styles/settings.css +110 -0
  48. package/bizar-dash/src/web/styles/tasks.css +305 -0
  49. package/bizar-dash/tests/mobile-chat.test.tsx +82 -0
  50. package/bizar-dash/tests/mobile-layout.test.tsx +296 -0
  51. package/bizar-dash/tests/mobile-misc.test.tsx +321 -0
  52. package/bizar-dash/tests/mobile-overview.test.tsx +214 -0
  53. package/bizar-dash/tests/mobile-settings.test.tsx +181 -0
  54. package/bizar-dash/tests/mobile-tasks.test.tsx +162 -0
  55. package/cli/commands/dash.mjs +5 -0
  56. package/cli/commands/tailscale.mjs +8 -1
  57. package/package.json +1 -1
  58. package/bizar-dash/dist/assets/MobileChat-OidrxXR9.js +0 -1
  59. package/bizar-dash/dist/assets/MobileSettings-B91gVFii.js +0 -1
  60. package/bizar-dash/dist/assets/MobileSettings-B91gVFii.js.map +0 -1
  61. package/bizar-dash/dist/assets/icons-Bd8piSb2.js.map +0 -1
  62. package/bizar-dash/dist/assets/main-6YUZY968.js +0 -19
  63. package/bizar-dash/dist/assets/main-6YUZY968.js.map +0 -1
  64. package/bizar-dash/dist/assets/mobile-CSsp30lr.js +0 -2
  65. package/bizar-dash/dist/assets/mobile-CSsp30lr.js.map +0 -1
  66. package/bizar-dash/dist/assets/mobile-DtwK7DOV.js +0 -1
  67. package/bizar-dash/dist/assets/mobile-DtwK7DOV.js.map +0 -1
  68. package/bizar-dash/dist/assets/useSlashCommands-DEkxEvOO.js +0 -2
  69. package/bizar-dash/dist/assets/useSlashCommands-DEkxEvOO.js.map +0 -1
@@ -1949,6 +1949,186 @@ code,
1949
1949
  }
1950
1950
  }
1951
1951
 
1952
+ /* ─── Mobile Overview (v5.4) ───────────────────────────────────────────── */
1953
+ .mobile-overview {
1954
+ display: flex;
1955
+ flex-direction: column;
1956
+ gap: 16px;
1957
+ }
1958
+
1959
+ .mobile-hero {
1960
+ padding: 20px 16px;
1961
+ background: linear-gradient(135deg, rgba(139, 92, 246, 0.15), rgba(59, 130, 246, 0.10));
1962
+ border: 1px solid var(--border);
1963
+ border-radius: 14px;
1964
+ }
1965
+
1966
+ .mobile-hero h1 {
1967
+ margin: 0 0 8px;
1968
+ font-size: 24px;
1969
+ font-weight: 700;
1970
+ line-height: 1.2;
1971
+ }
1972
+
1973
+ .mobile-hero p {
1974
+ margin: 0 0 12px;
1975
+ font-size: 13px;
1976
+ color: var(--text-dim);
1977
+ line-height: 1.4;
1978
+ }
1979
+
1980
+ .mobile-hero-input {
1981
+ width: 100%;
1982
+ background: var(--surface-2);
1983
+ border: 1px solid var(--border);
1984
+ border-radius: 8px;
1985
+ padding: 10px 12px;
1986
+ color: var(--text);
1987
+ font-size: 14px;
1988
+ font-family: inherit;
1989
+ resize: vertical;
1990
+ margin-bottom: 8px;
1991
+ box-sizing: border-box;
1992
+ }
1993
+
1994
+ .mobile-hero-submit {
1995
+ width: 100%;
1996
+ padding: 10px;
1997
+ background: var(--accent, #8b5cf6);
1998
+ color: white;
1999
+ border: none;
2000
+ border-radius: 8px;
2001
+ font-weight: 600;
2002
+ font-size: 14px;
2003
+ cursor: pointer;
2004
+ display: inline-flex;
2005
+ align-items: center;
2006
+ justify-content: center;
2007
+ gap: 6px;
2008
+ }
2009
+
2010
+ .mobile-hero-submit:disabled {
2011
+ opacity: 0.5;
2012
+ cursor: not-allowed;
2013
+ }
2014
+
2015
+ .mobile-stats-stack {
2016
+ display: flex;
2017
+ flex-direction: column;
2018
+ gap: 8px;
2019
+ }
2020
+
2021
+ .mobile-stat-card {
2022
+ display: flex;
2023
+ align-items: center;
2024
+ gap: 14px;
2025
+ padding: 14px 16px;
2026
+ background: var(--surface-1);
2027
+ border: 1px solid var(--border);
2028
+ border-radius: 10px;
2029
+ }
2030
+
2031
+ .mobile-stat-card.is-blue { border-left: 4px solid #58a6ff; }
2032
+ .mobile-stat-card.is-purple { border-left: 4px solid #8b5cf6; }
2033
+ .mobile-stat-card.is-green { border-left: 4px solid #3fb950; }
2034
+ .mobile-stat-card.is-yellow { border-left: 4px solid #d29922; }
2035
+
2036
+ .mobile-stat-icon {
2037
+ display: flex;
2038
+ align-items: center;
2039
+ justify-content: center;
2040
+ width: 40px;
2041
+ height: 40px;
2042
+ border-radius: 10px;
2043
+ background: var(--surface-2);
2044
+ color: var(--text);
2045
+ flex-shrink: 0;
2046
+ }
2047
+
2048
+ .mobile-stat-body { flex: 1; min-width: 0; }
2049
+
2050
+ .mobile-stat-label {
2051
+ font-size: 12px;
2052
+ color: var(--text-dim);
2053
+ text-transform: uppercase;
2054
+ letter-spacing: 0.05em;
2055
+ }
2056
+
2057
+ .mobile-stat-value {
2058
+ font-size: 24px;
2059
+ font-weight: 700;
2060
+ margin-top: 2px;
2061
+ }
2062
+
2063
+ .mobile-stat-subtext {
2064
+ font-size: 11px;
2065
+ color: var(--text-dim);
2066
+ margin-top: 2px;
2067
+ }
2068
+
2069
+ .mobile-activity-card,
2070
+ .mobile-quick-actions {
2071
+ padding: 16px;
2072
+ background: var(--surface-1);
2073
+ border: 1px solid var(--border);
2074
+ border-radius: 10px;
2075
+ }
2076
+
2077
+ .mobile-activity-card h3 {
2078
+ margin: 0 0 12px;
2079
+ font-size: 14px;
2080
+ font-weight: 600;
2081
+ }
2082
+
2083
+ .mobile-activity-list {
2084
+ list-style: none;
2085
+ padding: 0;
2086
+ margin: 0;
2087
+ display: flex;
2088
+ flex-direction: column;
2089
+ gap: 8px;
2090
+ }
2091
+
2092
+ .mobile-activity-item {
2093
+ display: flex;
2094
+ gap: 8px;
2095
+ padding: 8px;
2096
+ border-radius: 6px;
2097
+ background: var(--surface-2);
2098
+ font-size: 12px;
2099
+ }
2100
+
2101
+ .mobile-activity-time {
2102
+ color: var(--text-dim);
2103
+ font-variant-numeric: tabular-nums;
2104
+ flex-shrink: 0;
2105
+ }
2106
+
2107
+ .mobile-activity-text {
2108
+ word-break: break-word;
2109
+ }
2110
+
2111
+ .mobile-quick-actions {
2112
+ display: flex;
2113
+ flex-direction: column;
2114
+ gap: 8px;
2115
+ }
2116
+
2117
+ .mobile-quick-action {
2118
+ display: flex;
2119
+ align-items: center;
2120
+ gap: 8px;
2121
+ padding: 12px;
2122
+ background: var(--surface-2);
2123
+ border: 1px solid var(--border);
2124
+ border-radius: 8px;
2125
+ color: var(--text);
2126
+ font-size: 14px;
2127
+ font-weight: 500;
2128
+ text-align: left;
2129
+ cursor: pointer;
2130
+ }
2131
+
1952
2132
  /* ─── Reduce motion ──────────────────────────────────────────────────── */
1953
2133
  @media (prefers-reduced-motion: reduce) {
1954
2134
  *,
@@ -761,3 +761,113 @@
761
761
  opacity: 0.5;
762
762
  }
763
763
 
764
+ /* ─────────────────────────────────────────────────────────────────────
765
+ v5.4 — Mobile settings accordion (mobile-settings)
766
+ ───────────────────────────────────────────────────────────────────── */
767
+
768
+ .mobile-settings {
769
+ padding: 16px;
770
+ }
771
+
772
+ .mobile-settings-search {
773
+ display: flex;
774
+ align-items: center;
775
+ gap: 8px;
776
+ padding: 10px 14px;
777
+ background: var(--surface-2, var(--bg-elev-2, #1e1e2e));
778
+ border: 1px solid var(--border, #3a3a4a);
779
+ border-radius: 10px;
780
+ margin-bottom: 16px;
781
+ color: var(--text-dim, #888);
782
+ }
783
+
784
+ .mobile-settings-search input {
785
+ flex: 1;
786
+ background: transparent;
787
+ border: none;
788
+ color: var(--text, #e0e0e0);
789
+ font-size: 15px;
790
+ outline: none;
791
+ }
792
+
793
+ .mobile-settings-list {
794
+ display: flex;
795
+ flex-direction: column;
796
+ gap: 8px;
797
+ }
798
+
799
+ .mobile-settings-item {
800
+ background: var(--surface-1, var(--bg-elev, #18181f));
801
+ border: 1px solid var(--border, #3a3a4a);
802
+ border-radius: 10px;
803
+ overflow: hidden;
804
+ }
805
+
806
+ .mobile-settings-item-head {
807
+ display: flex;
808
+ align-items: center;
809
+ gap: 12px;
810
+ width: 100%;
811
+ padding: 14px 16px;
812
+ background: transparent;
813
+ border: none;
814
+ color: var(--text, #e0e0e0);
815
+ text-align: left;
816
+ cursor: pointer;
817
+ }
818
+
819
+ .mobile-settings-item-icon {
820
+ display: flex;
821
+ align-items: center;
822
+ justify-content: center;
823
+ width: 32px;
824
+ height: 32px;
825
+ border-radius: 8px;
826
+ background: var(--surface-2, var(--bg-elev-2, #1e1e2e));
827
+ color: var(--accent, #8b5cf6);
828
+ flex-shrink: 0;
829
+ }
830
+
831
+ .mobile-settings-item-text {
832
+ flex: 1;
833
+ min-width: 0;
834
+ }
835
+
836
+ .mobile-settings-item-title {
837
+ font-size: 15px;
838
+ font-weight: 500;
839
+ }
840
+
841
+ .mobile-settings-item-desc {
842
+ font-size: 12px;
843
+ color: var(--text-dim, #888);
844
+ margin-top: 2px;
845
+ }
846
+
847
+ .mobile-settings-item-chevron {
848
+ color: var(--text-dim, #888);
849
+ transition: transform 200ms;
850
+ flex-shrink: 0;
851
+ }
852
+
853
+ .mobile-settings-item-chevron.is-rotated {
854
+ transform: rotate(90deg);
855
+ }
856
+
857
+ .mobile-settings-item.is-expanded {
858
+ border-color: var(--accent, #8b5cf6);
859
+ }
860
+
861
+ .mobile-settings-item-body {
862
+ padding: 0 16px 16px;
863
+ border-top: 1px solid var(--border, #3a3a4a);
864
+ background: var(--surface-2, var(--bg-elev-2, #1e1e2e));
865
+ }
866
+
867
+ .mobile-settings-empty {
868
+ padding: 24px 16px;
869
+ text-align: center;
870
+ color: var(--text-dim, #888);
871
+ font-size: 14px;
872
+ }
873
+
@@ -287,4 +287,309 @@
287
287
  justify-content: center;
288
288
  padding: var(--space-12);
289
289
  color: var(--text-dim);
290
+ }
291
+
292
+ /* ── Mobile Tasks (v5.4) ──────────────────────────────────────────── */
293
+
294
+ .mobile-tasks {
295
+ padding: 14px 16px 80px;
296
+ }
297
+
298
+ .mobile-tasks-search {
299
+ display: flex;
300
+ align-items: center;
301
+ gap: 8px;
302
+ padding: 10px 14px;
303
+ background: var(--surface-2);
304
+ border: 1px solid var(--border);
305
+ border-radius: 10px;
306
+ margin-bottom: 12px;
307
+ }
308
+
309
+ .mobile-tasks-search-icon {
310
+ color: var(--text-dim);
311
+ flex-shrink: 0;
312
+ }
313
+
314
+ .mobile-tasks-search-input {
315
+ flex: 1;
316
+ background: transparent;
317
+ border: 0;
318
+ outline: 0;
319
+ color: var(--text);
320
+ font-size: 14px;
321
+ font-family: inherit;
322
+ min-width: 0;
323
+ }
324
+
325
+ .mobile-tasks-search-input::placeholder {
326
+ color: var(--text-dim);
327
+ }
328
+
329
+ .mobile-tasks-tabs {
330
+ display: flex;
331
+ gap: 6px;
332
+ margin-bottom: 16px;
333
+ overflow-x: auto;
334
+ padding-bottom: 4px;
335
+ }
336
+
337
+ .mobile-tasks-tab {
338
+ display: flex;
339
+ align-items: center;
340
+ gap: 6px;
341
+ padding: 6px 12px;
342
+ background: var(--surface-2);
343
+ border: 1px solid var(--border);
344
+ border-radius: 14px;
345
+ color: var(--text-dim);
346
+ font-size: 12px;
347
+ white-space: nowrap;
348
+ cursor: pointer;
349
+ flex-shrink: 0;
350
+ }
351
+
352
+ .mobile-tasks-tab.is-active {
353
+ background: var(--accent);
354
+ color: white;
355
+ border-color: var(--accent);
356
+ }
357
+
358
+ .mobile-tasks-count {
359
+ background: rgba(255, 255, 255, 0.15);
360
+ padding: 0 6px;
361
+ border-radius: 8px;
362
+ font-size: 10px;
363
+ }
364
+
365
+ .mobile-tasks-list {
366
+ display: flex;
367
+ flex-direction: column;
368
+ gap: 8px;
369
+ }
370
+
371
+ /* ── Mobile task card ──────────────────────────────────────────────── */
372
+
373
+ .task-card-mobile {
374
+ background: var(--surface-1);
375
+ border: 1px solid var(--border);
376
+ border-radius: 10px;
377
+ overflow: hidden;
378
+ }
379
+
380
+ .task-card-mobile.is-todo,
381
+ .task-card-mobile.is-queued {
382
+ border-left: 4px solid #8b949e;
383
+ }
384
+
385
+ .task-card-mobile.is-doing {
386
+ border-left: 4px solid #d29922;
387
+ }
388
+
389
+ .task-card-mobile.is-done {
390
+ border-left: 4px solid #3fb950;
391
+ opacity: 0.7;
392
+ }
393
+
394
+ .task-card-mobile.is-failed,
395
+ .task-card-mobile.is-blocked {
396
+ border-left: 4px solid #f85149;
397
+ }
398
+
399
+ .task-card-mobile-head {
400
+ display: flex;
401
+ align-items: center;
402
+ gap: 10px;
403
+ padding: 12px 14px;
404
+ cursor: pointer;
405
+ }
406
+
407
+ .task-card-mobile-status {
408
+ width: 8px;
409
+ height: 8px;
410
+ border-radius: 50%;
411
+ background: var(--text-dim);
412
+ flex-shrink: 0;
413
+ }
414
+
415
+ .task-card-mobile-status.is-doing { background: #d29922; }
416
+ .task-card-mobile-status.is-done { background: #3fb950; }
417
+ .task-card-mobile-status.is-failed { background: #f85149; }
418
+ .task-card-mobile-status.is-blocked { background: #f85149; }
419
+
420
+ .task-card-mobile-body {
421
+ flex: 1;
422
+ min-width: 0;
423
+ }
424
+
425
+ .task-card-mobile-title {
426
+ font-size: 14px;
427
+ font-weight: 500;
428
+ white-space: nowrap;
429
+ overflow: hidden;
430
+ text-overflow: ellipsis;
431
+ }
432
+
433
+ .task-priority-badge {
434
+ display: inline-block;
435
+ font-size: 10px;
436
+ padding: 1px 6px;
437
+ border-radius: 6px;
438
+ margin-top: 2px;
439
+ }
440
+
441
+ .task-priority-badge.is-high {
442
+ background: rgba(239, 68, 68, 0.2);
443
+ color: #f85149;
444
+ }
445
+
446
+ .task-priority-badge.is-medium {
447
+ background: rgba(210, 153, 34, 0.2);
448
+ color: #d29922;
449
+ }
450
+
451
+ .task-priority-badge.is-low {
452
+ background: rgba(63, 185, 80, 0.2);
453
+ color: #3fb950;
454
+ }
455
+
456
+ .task-chevron {
457
+ flex-shrink: 0;
458
+ color: var(--text-dim);
459
+ transition: transform 150ms ease;
460
+ }
461
+
462
+ .task-chevron.is-rotated {
463
+ transform: rotate(90deg);
464
+ }
465
+
466
+ .task-card-mobile-details {
467
+ padding: 0 14px 12px;
468
+ border-top: 1px solid var(--border);
469
+ background: var(--surface-2);
470
+ }
471
+
472
+ .task-card-mobile-desc {
473
+ font-size: 13px;
474
+ color: var(--text-dim);
475
+ margin: 8px 0;
476
+ line-height: 1.4;
477
+ }
478
+
479
+ .task-card-mobile-meta {
480
+ display: flex;
481
+ flex-wrap: wrap;
482
+ gap: 8px;
483
+ margin: 8px 0;
484
+ font-size: 12px;
485
+ color: var(--text-dim);
486
+ }
487
+
488
+ .task-card-mobile-meta .tag {
489
+ background: var(--surface-1);
490
+ border: 1px solid var(--border);
491
+ border-radius: 6px;
492
+ padding: 1px 6px;
493
+ font-size: 11px;
494
+ }
495
+
496
+ .task-card-mobile-actions {
497
+ display: flex;
498
+ gap: 6px;
499
+ margin-top: 8px;
500
+ }
501
+
502
+ /* ── Bottom sheet ─────────────────────────────────────────────────── */
503
+
504
+ .sheet-backdrop {
505
+ position: fixed;
506
+ inset: 0;
507
+ background: rgba(0, 0, 0, 0.5);
508
+ z-index: 60;
509
+ }
510
+
511
+ .sheet-bottom {
512
+ position: fixed;
513
+ bottom: 0;
514
+ left: 0;
515
+ right: 0;
516
+ background: var(--surface-1);
517
+ border-top: 1px solid var(--border);
518
+ border-radius: 16px 16px 0 0;
519
+ padding: 12px 16px 24px;
520
+ z-index: 70;
521
+ max-height: 80vh;
522
+ overflow-y: auto;
523
+ }
524
+
525
+ .sheet-handle {
526
+ width: 36px;
527
+ height: 4px;
528
+ background: var(--text-dim);
529
+ border-radius: 2px;
530
+ margin: 0 auto 12px;
531
+ }
532
+
533
+ .sheet-title {
534
+ margin: 0 0 12px;
535
+ font-size: 18px;
536
+ font-weight: 600;
537
+ color: var(--text-strong);
538
+ }
539
+
540
+ .sheet-input,
541
+ .sheet-textarea {
542
+ width: 100%;
543
+ padding: 10px 12px;
544
+ background: var(--surface-2);
545
+ border: 1px solid var(--border);
546
+ border-radius: 8px;
547
+ color: var(--text);
548
+ font-size: 15px;
549
+ font-family: inherit;
550
+ margin-bottom: 10px;
551
+ outline: none;
552
+ transition: border-color 120ms ease;
553
+ }
554
+
555
+ .sheet-input:focus,
556
+ .sheet-textarea:focus {
557
+ border-color: var(--accent);
558
+ }
559
+
560
+ .sheet-priority {
561
+ display: flex;
562
+ gap: 6px;
563
+ margin-bottom: 12px;
564
+ }
565
+
566
+ .sheet-priority-btn {
567
+ flex: 1;
568
+ padding: 8px;
569
+ background: var(--surface-2);
570
+ border: 1px solid var(--border);
571
+ border-radius: 8px;
572
+ color: var(--text);
573
+ font-size: 13px;
574
+ text-transform: capitalize;
575
+ cursor: pointer;
576
+ transition: background 120ms ease;
577
+ }
578
+
579
+ .sheet-priority-btn.is-active.is-high {
580
+ background: rgba(239, 68, 68, 0.2);
581
+ }
582
+
583
+ .sheet-priority-btn.is-active.is-medium {
584
+ background: rgba(210, 153, 34, 0.2);
585
+ }
586
+
587
+ .sheet-priority-btn.is-active.is-low {
588
+ background: rgba(63, 185, 80, 0.2);
589
+ }
590
+
591
+ .sheet-actions {
592
+ display: flex;
593
+ gap: 8px;
594
+ justify-content: flex-end;
290
595
  }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * tests/mobile-chat.test.tsx
3
+ *
4
+ * v5.4 — Mobile chat smoke tests.
5
+ */
6
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
7
+ import { render, screen } from '@testing-library/react';
8
+ import React from 'react';
9
+ import { MobileChat } from '../src/web/mobile/MobileChat';
10
+ import type { Snapshot, Settings, ChatMessage, ChatSession } from '../src/web/lib/types';
11
+
12
+ const mockSnapshot = (overrides: Partial<Snapshot> = {}): Snapshot => ({
13
+ overview: {
14
+ counts: { agents: 0, plans: 0, projects: 0, sessions: 0, activeProject: null },
15
+ recentActivity: [],
16
+ versions: { node: '', platform: '', projectRoot: '', bizarRoot: '' },
17
+ generatedAt: new Date().toISOString(),
18
+ },
19
+ agents: [],
20
+ artifacts: [],
21
+ projects: [],
22
+ activeProject: null,
23
+ config: { path: '', data: {}, raw: '', exists: false },
24
+ settings: {
25
+ path: '',
26
+ data: {
27
+ theme: {
28
+ mode: 'dark',
29
+ accent: '#8b5cf6',
30
+ success: '#3fb950',
31
+ warning: '#d29922',
32
+ error: '#f85149',
33
+ info: '#58a6ff',
34
+ fontFamily: '',
35
+ fontSize: 14,
36
+ compactMode: false,
37
+ animations: true,
38
+ },
39
+ ui: { layout: 'topnav', showHeader: true, showStatusBar: true, defaultTab: '' },
40
+ defaultAgent: 'odin',
41
+ defaultModel: '',
42
+ notifications: { onAgentComplete: false, onPlanApproval: false },
43
+ dashboard: { autoLaunchWeb: false },
44
+ service: { enabled: false, autostart: false },
45
+ about: { version: '', homepage: '', license: '' },
46
+ agents: { maxParallel: 1, stuckThresholdMs: 0, autoRestart: false },
47
+ personalization: { displayName: '', role: '', team: '', aboutMe: '', preferences: '' },
48
+ workflow: { artifactsEnabled: false, agentsDecideAutonomously: false, chatAutonomous: false },
49
+ } as Settings,
50
+ exists: false,
51
+ },
52
+ tasks: [],
53
+ mods: [],
54
+ schedules: [],
55
+ providers: [],
56
+ mcps: [],
57
+ ...overrides,
58
+ });
59
+
60
+ describe('MobileChat', () => {
61
+ beforeEach(() => {
62
+ vi.clearAllMocks();
63
+ });
64
+
65
+ it('renders the chat shell', () => {
66
+ render(<MobileChat snapshot={mockSnapshot()} settings={mockSnapshot().settings!.data} />);
67
+ expect(document.querySelector('.chat-shell')).toBeInTheDocument();
68
+ });
69
+
70
+ it('shows the top bar with project name', () => {
71
+ const snap = mockSnapshot({
72
+ activeProject: { id: 'proj-1', name: 'My Project', path: '/test', status: 'active' },
73
+ });
74
+ render(<MobileChat snapshot={snap} settings={snap.settings!.data} />);
75
+ expect(screen.getByText('My Project')).toBeInTheDocument();
76
+ });
77
+
78
+ it('renders composer with send button', () => {
79
+ render(<MobileChat snapshot={mockSnapshot()} settings={mockSnapshot().settings!.data} />);
80
+ expect(document.querySelector('.chat-composer-pill')).toBeInTheDocument();
81
+ });
82
+ });