@adatechnology/conversations-ui 0.1.0-rc.9 → 0.1.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 (129) hide show
  1. package/dist/ConversationSimulatorPanel--5fIzXWY.d.ts +804 -0
  2. package/dist/{chunk-G5BM3VBP.js → chunk-BJNRLLDO.js} +1248 -282
  3. package/dist/chunk-DKPXKQGC.js +110 -0
  4. package/dist/{chunk-2AYDBWNE.js → chunk-WCBDXZ3X.js} +13 -3
  5. package/dist/flows/index.d.ts +422 -5
  6. package/dist/flows/index.js +2502 -676
  7. package/dist/index.d.ts +919 -17
  8. package/dist/index.js +3676 -675
  9. package/dist/preview/index.d.ts +62 -105
  10. package/dist/preview/index.js +162 -284
  11. package/dist/styles.css +893 -0
  12. package/package.json +9 -8
  13. package/src/AudioPlayer.tsx +8 -0
  14. package/src/AudioRecorderButton.test.tsx +30 -0
  15. package/src/AudioRecorderButton.tsx +248 -0
  16. package/src/AudioTranscription.test.tsx +115 -0
  17. package/src/AudioTranscription.tsx +252 -0
  18. package/src/Avatar.tsx +1 -1
  19. package/src/ConversationContextPanel.tsx +218 -44
  20. package/src/ConversationDocumentsPanel.tsx +11 -6
  21. package/src/ConversationHeader.test.tsx +66 -0
  22. package/src/ConversationHeader.tsx +147 -47
  23. package/src/ConversationListItem.tsx +8 -6
  24. package/src/ConversationLocalesProvider.tsx +28 -0
  25. package/src/ConversationRow.tsx +53 -7
  26. package/src/DarkModeToggle.test.tsx +76 -0
  27. package/src/DarkModeToggle.tsx +92 -0
  28. package/src/DocumentsLibrary.tsx +67 -7
  29. package/src/EmojiPicker.tsx +2 -1
  30. package/src/InteractiveMessage.tsx +3 -0
  31. package/src/Lightbox.tsx +1 -1
  32. package/src/MediaRenderer.tsx +88 -15
  33. package/src/MessageBubble.test.tsx +41 -0
  34. package/src/MessageBubble.tsx +47 -5
  35. package/src/MessageComposer.test.tsx +35 -0
  36. package/src/MessageComposer.tsx +122 -17
  37. package/src/MessageText.tsx +2 -1
  38. package/src/MessageTimestamp.tsx +2 -1
  39. package/src/RichMessageComposer.test.tsx +113 -0
  40. package/src/RichMessageComposer.tsx +551 -0
  41. package/src/SimpleEmojiPicker.tsx +5 -3
  42. package/src/StatusTicks.tsx +1 -1
  43. package/src/Toast.tsx +4 -0
  44. package/src/Tooltip.test.ts +42 -0
  45. package/src/Tooltip.tsx +167 -0
  46. package/src/Wallpaper.tsx +27 -13
  47. package/src/WhatsAppMessageEditor.tsx +10 -7
  48. package/src/WindowExpiredNotice.tsx +12 -4
  49. package/src/{preview/audioRecorderFormat.test.ts → audioRecorderFormat.test.ts} +1 -1
  50. package/src/buildOutput.test.ts +79 -0
  51. package/src/composer.constant.ts +33 -0
  52. package/src/conversationTranscript.test.ts +57 -0
  53. package/src/conversationTranscript.ts +29 -4
  54. package/src/conversationWindow.ts +7 -5
  55. package/src/documentTypeLabel.test.ts +57 -0
  56. package/src/documents/DocumentsWorkspace.tsx +550 -0
  57. package/src/documents/index.ts +8 -0
  58. package/src/documents/labels.ts +92 -0
  59. package/src/flows/FlowConnectionEdge.tsx +104 -0
  60. package/src/flows/FlowGroupHeader.tsx +12 -2
  61. package/src/flows/FlowLegend.tsx +125 -0
  62. package/src/flows/FlowMapCanvas.tsx +15 -12
  63. package/src/flows/FlowMapNode.tsx +4 -1
  64. package/src/flows/FlowNodeCard.tsx +219 -34
  65. package/src/flows/FlowNodePanel.tsx +153 -39
  66. package/src/flows/FlowPalette.tsx +156 -70
  67. package/src/flows/FlowPortalNode.tsx +1 -1
  68. package/src/flows/FlowWhatsAppPreview.tsx +14 -3
  69. package/src/flows/FlowsWorkspace.tsx +1255 -0
  70. package/src/flows/flowCanvasModel.test.ts +456 -0
  71. package/src/flows/flowCanvasModel.ts +378 -0
  72. package/src/flows/flowEditorOps.test.ts +276 -0
  73. package/src/flows/flowEditorOps.ts +202 -0
  74. package/src/flows/flowGraph.ts +78 -53
  75. package/src/flows/flowMenuPlacement.test.ts +130 -0
  76. package/src/flows/flowMenuPlacement.ts +86 -0
  77. package/src/flows/index.ts +51 -2
  78. package/src/flows/labels.ts +180 -0
  79. package/src/flows/workspaceContract.test.ts +126 -0
  80. package/src/hooks/useContainerWidth.ts +35 -0
  81. package/src/hooks/useConversationRealtime.ts +10 -8
  82. package/src/hooks/useScrollToLatestMessage.ts +127 -0
  83. package/src/hooks/useUrlFilterState.ts +107 -0
  84. package/src/icon.constant.ts +12 -0
  85. package/src/index.ts +100 -0
  86. package/src/lib/composer-formatting.test.ts +78 -0
  87. package/src/lib/composer-formatting.ts +145 -0
  88. package/src/lib/whatsapp-formatting.test.tsx +37 -0
  89. package/src/lib/whatsapp-formatting.tsx +28 -3
  90. package/src/listing/index.tsx +202 -0
  91. package/src/pagination.constant.ts +10 -0
  92. package/src/preview/ConversationPreview.tsx +84 -45
  93. package/src/preview/ConversationSimulatorClient.ts +143 -0
  94. package/src/preview/ConversationSimulatorPanel.test.tsx +55 -0
  95. package/src/preview/ConversationSimulatorPanel.tsx +131 -0
  96. package/src/preview/createPreviewBridgeClient.test.ts +92 -0
  97. package/src/preview/createPreviewBridgeClient.ts +124 -0
  98. package/src/preview/createPreviewMediaUploader.ts +82 -0
  99. package/src/preview/createPreviewWebhookClient.test.ts +96 -0
  100. package/src/preview/createPreviewWebhookClient.ts +99 -3
  101. package/src/preview/index.ts +36 -2
  102. package/src/preview/previewMediaUploader.test.ts +61 -0
  103. package/src/providers/ConversationsProvider.tsx +8 -6
  104. package/src/providers/types.ts +59 -2
  105. package/src/quickReply.test.ts +58 -0
  106. package/src/replyLatency.test.ts +71 -0
  107. package/src/replyLatency.ts +57 -0
  108. package/src/settings/MessagesWorkspace.tsx +571 -0
  109. package/src/settings/TopicsForm.tsx +2 -0
  110. package/src/settings/TranscriptionSettingsForm.test.tsx +81 -0
  111. package/src/settings/TranscriptionSettingsForm.tsx +190 -0
  112. package/src/settings/WelcomeFarewellForm.tsx +1 -0
  113. package/src/settings/WhatsAppCreateTemplateForm.tsx +1 -0
  114. package/src/settings/WhatsAppTemplateSettingsForm.tsx +5 -2
  115. package/src/settings/WhatsAppTemplatesSettings.test.tsx +61 -0
  116. package/src/settings/WhatsAppTemplatesSettings.tsx +22 -2
  117. package/src/styles.css +858 -0
  118. package/src/theme.ts +13 -0
  119. package/src/types.ts +26 -0
  120. package/src/workspace/BulkTemplateModal.tsx +132 -0
  121. package/src/workspace/ConversationPane.tsx +432 -0
  122. package/src/workspace/ConversationsInboxList.tsx +194 -0
  123. package/src/workspace/ConversationsWorkspace.tsx +423 -0
  124. package/src/workspace/index.ts +17 -0
  125. package/src/workspace/labels.test.ts +17 -0
  126. package/src/workspace/labels.ts +85 -0
  127. package/src/workspace/useConversationsInbox.ts +332 -0
  128. package/dist/types-B5C1DLu1.d.ts +0 -365
  129. package/src/preview/AudioRecorderButton.tsx +0 -117
package/src/styles.css CHANGED
@@ -22,7 +22,12 @@
22
22
 
23
23
  /* Botão de ação do cabeçalho de conversa e do aviso de janela. Vive no stylesheet, como o
24
24
  .cv-wallpaper, para não depender da configuração de Tailwind do consumidor. */
25
+ /* `inline-flex` com gap em todo controle com ícone: o ícone é SVG e, como elemento inline, assentava
26
+ na baseline do texto — o traço ficava um fio abaixo do rótulo em cada botão. */
25
27
  .cv-header-action {
28
+ display: inline-flex;
29
+ align-items: center;
30
+ gap: 0.375rem;
26
31
  border: 1px solid rgb(203 213 225);
27
32
  border-radius: 0.375rem;
28
33
  padding: 0.375rem 0.75rem;
@@ -34,6 +39,9 @@
34
39
  .dark .cv-header-action { border-color: rgb(71 85 105); color: rgb(226 232 240); }
35
40
 
36
41
  .cv-header-icon {
42
+ display: inline-flex;
43
+ align-items: center;
44
+ justify-content: center;
37
45
  border: 1px solid rgb(203 213 225);
38
46
  border-radius: 0.5rem;
39
47
  padding: 0.375rem 0.5rem;
@@ -100,6 +108,9 @@
100
108
 
101
109
  /* Voltar do master/detail: existe só onde lista e conversa não cabem lado a lado. */
102
110
  .cv-back {
111
+ display: inline-flex;
112
+ align-items: center;
113
+ justify-content: center;
103
114
  border: 1px solid rgb(203 213 225);
104
115
  border-radius: 0.5rem;
105
116
  padding: 0.25rem 0.5rem;
@@ -110,6 +121,13 @@
110
121
  @media (min-width: 1024px) { .cv-back { display: none; } }
111
122
  .dark .cv-back { border-color: rgb(71 85 105); color: rgb(226 232 240); }
112
123
 
124
+ /* Contador do cabeçalho da inbox: ícone e número na mesma linha de base ótica. */
125
+ .cv-stat {
126
+ display: inline-flex;
127
+ align-items: center;
128
+ gap: 0.25rem;
129
+ }
130
+
113
131
  /* Utilitários de densidade: em tela estreita o texto das ações vira ícone, porque rótulo longo
114
132
  empilha e come a altura útil da conversa. */
115
133
  .cv-only-wide { display: none; }
@@ -155,3 +173,843 @@
155
173
  max-width: calc(100vw - 1.5rem);
156
174
  }
157
175
  }
176
+
177
+ /**
178
+ * Scrollbar fina — paridade com `.scrollbar-thin` de
179
+ * financiamento-imobiliario-bot/apps/web/src/index.css.
180
+ *
181
+ * Prefixo `cv-` porque o host pode ter a própria `.scrollbar-thin` (plugin do Tailwind ou CSS
182
+ * próprio): colidir no nome faria o painel herdar regra alheia sem ninguém entender por quê.
183
+ *
184
+ * Usada onde a área rola dentro de um bloco de altura limitada, como o grid de "Suas Seleções":
185
+ * a barra padrão do sistema ocupa ~15px e, num card de 3 colunas, come uma coluna inteira.
186
+ */
187
+ .cv-scrollbar-thin {
188
+ scrollbar-width: thin;
189
+ scrollbar-color: rgba(0, 0, 0, 0.15) transparent;
190
+ }
191
+ .cv-scrollbar-thin::-webkit-scrollbar { width: 4px; height: 4px; }
192
+ .cv-scrollbar-thin::-webkit-scrollbar-track { background: transparent; }
193
+ .cv-scrollbar-thin::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, 0.15); border-radius: 2px; }
194
+ .cv-scrollbar-thin::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, 0.3); }
195
+ .dark .cv-scrollbar-thin { scrollbar-color: rgba(255, 255, 255, 0.15) transparent; }
196
+ .dark .cv-scrollbar-thin::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); }
197
+ .dark .cv-scrollbar-thin::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.3); }
198
+
199
+ /**
200
+ * Mãozinha no que é clicável.
201
+ *
202
+ * O Preflight do Tailwind v3 punha `cursor: pointer` em `button`; o v4 removeu, e sem regra
203
+ * explícita o botão herda o `cursor: default` do browser — os componentes deste pacote deixam de
204
+ * parecer clicáveis num host v4. São 91 botões aqui: carimbar a classe em cada um seria ruído que o
205
+ * próximo componente esqueceria de repetir.
206
+ *
207
+ * `:where()` zera a especificidade de propósito: a regra vence o UA stylesheet (autor sempre vence)
208
+ * mas perde de qualquer regra do host, então quem quiser outro cursor não precisa de `!important`.
209
+ */
210
+ :where(button:not(:disabled), [role='button']:not(:disabled), summary) {
211
+ cursor: pointer;
212
+ }
213
+
214
+ /**
215
+ * Simulador de cliente. Largura fixa porque é painel auxiliar: a thread ao lado é que deve
216
+ * ganhar o espaço restante quando a janela encolhe.
217
+ */
218
+ .cv-simulator-panel {
219
+ display: flex;
220
+ flex-direction: column;
221
+ width: 24rem;
222
+ flex-shrink: 0;
223
+ border-left: 1px solid rgb(229 231 235);
224
+ background: #fff;
225
+ }
226
+
227
+ .cv-simulator-panel__header {
228
+ display: flex;
229
+ align-items: center;
230
+ justify-content: space-between;
231
+ gap: 0.5rem;
232
+ padding: 0.75rem 1rem;
233
+ border-bottom: 1px solid rgb(229 231 235);
234
+ }
235
+
236
+ .cv-simulator-panel__heading { min-width: 0; }
237
+
238
+ .cv-simulator-panel__title {
239
+ font-size: 0.875rem;
240
+ font-weight: 600;
241
+ color: rgb(17 24 39);
242
+ overflow: hidden;
243
+ text-overflow: ellipsis;
244
+ white-space: nowrap;
245
+ }
246
+
247
+ .cv-simulator-panel__subtitle {
248
+ font-size: 0.75rem;
249
+ color: rgb(156 163 175);
250
+ overflow: hidden;
251
+ text-overflow: ellipsis;
252
+ white-space: nowrap;
253
+ }
254
+
255
+ .cv-simulator-panel__actions {
256
+ display: flex;
257
+ align-items: center;
258
+ gap: 0.25rem;
259
+ }
260
+
261
+ .cv-simulator-panel__close {
262
+ display: inline-flex;
263
+ padding: 0.375rem;
264
+ border: 0;
265
+ border-radius: 0.5rem;
266
+ background: transparent;
267
+ color: rgb(156 163 175);
268
+ transition: color 150ms, background-color 150ms;
269
+ }
270
+
271
+ .cv-simulator-panel__close:hover {
272
+ color: rgb(55 65 81);
273
+ background: rgb(243 244 246);
274
+ }
275
+
276
+ /* `min-height: 0` para o transcript rolar dentro do painel em vez de esticar o `<aside>`. */
277
+ .cv-simulator-panel__body { flex: 1; min-height: 0; }
278
+
279
+ .dark .cv-simulator-panel {
280
+ border-left-color: rgb(31 41 55);
281
+ background: rgb(17 24 39);
282
+ }
283
+ .dark .cv-simulator-panel__header { border-bottom-color: rgb(31 41 55); }
284
+ .dark .cv-simulator-panel__title { color: rgb(243 244 246); }
285
+ .dark .cv-simulator-panel__subtitle { color: rgb(107 114 128); }
286
+ .dark .cv-simulator-panel__close:hover { color: rgb(229 231 235); background: rgb(31 41 55); }
287
+
288
+ /* Painel auxiliar não cabe ao lado da thread em tela estreita: vira sobreposição de tela cheia. */
289
+ @media (max-width: 1023px) {
290
+ .cv-simulator-panel {
291
+ position: fixed;
292
+ inset: 0;
293
+ width: 100%;
294
+ z-index: 40;
295
+ border-left: 0;
296
+ }
297
+ }
298
+
299
+ /**
300
+ * Workspace de atendimento: a grade da tela inteira (lista · conversa · simulador).
301
+ *
302
+ * Cada coluna é um cartão sobre fundo neutro, com respiro entre elas — separação por espaço lê mais
303
+ * rápido que por borda. Todas as alturas presas em `min-height: 0` porque, em grid e flex, o padrão
304
+ * é não encolher abaixo do conteúdo: sem isso o scroll interno nunca ativa e quem rola é a página.
305
+ */
306
+ .cv-workspace {
307
+ display: flex;
308
+ flex-direction: column;
309
+ height: 100%;
310
+ min-height: 0;
311
+ }
312
+
313
+ .cv-workspace-header {
314
+ display: flex;
315
+ align-items: center;
316
+ justify-content: space-between;
317
+ gap: 0.5rem;
318
+ padding: 0.75rem 1rem;
319
+ border-bottom: 1px solid rgb(229 231 235);
320
+ }
321
+ .dark .cv-workspace-header { border-color: rgb(51 65 85); }
322
+
323
+ .cv-workspace-header__titles { min-width: 0; }
324
+ .cv-workspace-header__titles h1 {
325
+ font-size: 1.125rem;
326
+ font-weight: 600;
327
+ overflow: hidden;
328
+ text-overflow: ellipsis;
329
+ white-space: nowrap;
330
+ }
331
+ .cv-workspace-header__titles p {
332
+ display: flex;
333
+ flex-wrap: wrap;
334
+ gap: 0.25rem 0.75rem;
335
+ font-size: 0.875rem;
336
+ color: rgb(107 114 128);
337
+ }
338
+ .cv-workspace-header__waiting { color: rgb(217 119 6); }
339
+ .dark .cv-workspace-header__waiting { color: rgb(251 191 36); }
340
+
341
+ .cv-workspace-header__actions {
342
+ display: flex;
343
+ flex-shrink: 0;
344
+ align-items: center;
345
+ gap: 0.5rem;
346
+ }
347
+
348
+ .cv-workspace-toggle {
349
+ display: inline-flex;
350
+ align-items: center;
351
+ gap: 0.375rem;
352
+ border: 1px solid rgb(229 231 235);
353
+ border-radius: 0.375rem;
354
+ padding: 0.5rem 0.75rem;
355
+ font-size: 0.875rem;
356
+ /* 44px de área de toque em mobile — abaixo disso o dedo erra o alvo. */
357
+ min-height: 2.75rem;
358
+ }
359
+ .cv-workspace-toggle:disabled { opacity: 0.5; }
360
+ .cv-workspace-toggle--on { background: rgb(37 99 235); color: #fff; border-color: rgb(37 99 235); }
361
+ .dark .cv-workspace-toggle { border-color: rgb(71 85 105); color: rgb(226 232 240); }
362
+
363
+ .cv-workspace-failure {
364
+ border-bottom: 1px solid rgb(253 230 138);
365
+ background: rgb(255 251 235);
366
+ padding: 0.5rem 1rem;
367
+ font-size: 0.875rem;
368
+ color: rgb(146 64 14);
369
+ }
370
+ .dark .cv-workspace-failure { background: rgb(69 26 3); color: rgb(253 230 138); border-color: rgb(120 53 15); }
371
+
372
+ .cv-workspace-grid {
373
+ display: grid;
374
+ flex: 1;
375
+ min-height: 0;
376
+ grid-template-columns: minmax(0, 1fr);
377
+ gap: 0.75rem;
378
+ padding: 0.75rem;
379
+ background: rgb(243 244 246);
380
+ }
381
+ .dark .cv-workspace-grid { background: rgb(17 24 39); }
382
+
383
+ .cv-workspace-list,
384
+ .cv-workspace-detail,
385
+ .cv-workspace-simulator {
386
+ display: flex;
387
+ flex-direction: column;
388
+ min-height: 0;
389
+ min-width: 0;
390
+ overflow: hidden;
391
+ border: 1px solid rgb(229 231 235);
392
+ border-radius: 0.75rem;
393
+ background: #fff;
394
+ }
395
+ .dark .cv-workspace-list,
396
+ .dark .cv-workspace-detail,
397
+ .dark .cv-workspace-simulator { background: rgb(31 41 55); border-color: rgb(51 65 85); }
398
+
399
+ /* Em linha, e não em coluna: o painel do simulador não tem teto de altura — empilhado ele cresce
400
+ com o transcript e transborda o cartão; em linha herda a altura da faixa e rola por dentro. */
401
+ .cv-workspace-simulator { flex-direction: row; }
402
+
403
+ /* Master/detail abaixo de 1024px: com conversa aberta, some a lista; sem ela, some o detalhe.
404
+ Empilhar os dois na mesma altura fixa dava duas fatias inúteis. */
405
+ @media (max-width: 1023px) {
406
+ .cv-workspace-grid[data-detail='open'] .cv-workspace-list { display: none; }
407
+ .cv-workspace-grid[data-detail='closed'] .cv-workspace-detail { display: none; }
408
+ }
409
+
410
+ @media (min-width: 1024px) {
411
+ .cv-workspace-grid { grid-template-columns: 360px minmax(0, 1fr); }
412
+ /* Entre `lg` e `xl` as três não cabem — sobrariam ~100px para a conversa e o texto quebraria uma
413
+ palavra por linha. Enquanto se testa UMA conversa, é a lista que menos importa. */
414
+ .cv-workspace-grid--with-simulator { grid-template-columns: minmax(0, 1fr) 24rem; }
415
+ .cv-workspace-grid--with-simulator .cv-workspace-list { display: none; }
416
+ }
417
+
418
+ @media (min-width: 1280px) {
419
+ .cv-workspace-grid--with-simulator { grid-template-columns: 320px minmax(0, 1fr) 24rem; }
420
+ .cv-workspace-grid--with-simulator .cv-workspace-list { display: flex; }
421
+ }
422
+
423
+ .cv-workspace-pane {
424
+ display: flex;
425
+ flex-direction: column;
426
+ height: 100%;
427
+ min-height: 0;
428
+ }
429
+
430
+ .cv-workspace-transcript {
431
+ position: relative;
432
+ flex: 1;
433
+ min-height: 0;
434
+ overflow-y: auto;
435
+ padding: 0.75rem 1rem;
436
+ }
437
+
438
+ .cv-workspace-failure__link {
439
+ text-decoration: underline;
440
+ }
441
+
442
+ .cv-workspace-selection {
443
+ display: flex;
444
+ align-items: center;
445
+ justify-content: space-between;
446
+ gap: 0.5rem;
447
+ border-top: 1px solid #bfdbfe;
448
+ background: #eff6ff;
449
+ padding: 0.5rem 0.75rem;
450
+ font-size: 0.8125rem;
451
+ color: #1d4ed8;
452
+ }
453
+
454
+ .cv-workspace-selection__actions {
455
+ display: flex;
456
+ gap: 0.5rem;
457
+ }
458
+
459
+ .cv-workspace-selection__actions button {
460
+ min-height: 2.75rem;
461
+ border-radius: 0.375rem;
462
+ border: 1px solid #bfdbfe;
463
+ padding: 0 0.625rem;
464
+ }
465
+
466
+ .dark .cv-workspace-selection {
467
+ border-color: #1e40af;
468
+ background: rgb(23 37 84 / 40%);
469
+ color: #93c5fd;
470
+ }
471
+
472
+ .dark .cv-workspace-selection__actions button {
473
+ border-color: #1e40af;
474
+ }
475
+
476
+ .cv-workspace-notice {
477
+ border-top: 1px solid var(--cv-border, #e5e7eb);
478
+ background: #f3f4f6;
479
+ padding: 0.75rem 1rem;
480
+ text-align: center;
481
+ font-size: 0.875rem;
482
+ color: #6b7280;
483
+ }
484
+
485
+ .dark .cv-workspace-notice {
486
+ border-top-color: #374151;
487
+ background: #1f2937;
488
+ color: #9ca3af;
489
+ }
490
+
491
+ .cv-workspace-alert {
492
+ border-top: 1px solid rgb(254 202 202);
493
+ background: rgb(254 242 242);
494
+ padding: 0.5rem 1rem;
495
+ font-size: 0.875rem;
496
+ color: rgb(185 28 28);
497
+ }
498
+ .dark .cv-workspace-alert { background: rgb(69 10 10); color: rgb(252 165 165); border-color: rgb(127 29 29); }
499
+
500
+ .cv-workspace-filters {
501
+ display: flex;
502
+ flex-direction: column;
503
+ gap: 0.5rem;
504
+ padding: 0.75rem;
505
+ border-bottom: 1px solid rgb(229 231 235);
506
+ }
507
+ .dark .cv-workspace-filters { border-color: rgb(51 65 85); }
508
+
509
+ .cv-workspace-search {
510
+ width: 100%;
511
+ border: 1px solid rgb(229 231 235);
512
+ border-radius: 0.375rem;
513
+ padding: 0.5rem 0.75rem;
514
+ font-size: 0.875rem;
515
+ background: transparent;
516
+ }
517
+ .dark .cv-workspace-search { border-color: rgb(71 85 105); color: rgb(226 232 240); }
518
+
519
+ /* Linha única com rolagem, e não wrap: quebrando, a fila de janelas empurrava a categoria e a
520
+ lista para baixo toda vez que a coluna estreitava. */
521
+ .cv-workspace-chips {
522
+ display: flex;
523
+ flex-wrap: nowrap;
524
+ align-items: center;
525
+ gap: 0.375rem;
526
+ font-size: 0.75rem;
527
+ overflow-x: auto;
528
+ scrollbar-width: none;
529
+ }
530
+ .cv-workspace-chips::-webkit-scrollbar { display: none; }
531
+ .cv-workspace-chips__legend { color: rgb(107 114 128); flex-shrink: 0; }
532
+ .cv-workspace-chip {
533
+ display: flex;
534
+ flex-shrink: 0;
535
+ align-items: center;
536
+ gap: 0.25rem;
537
+ white-space: nowrap;
538
+ border-radius: 0.375rem;
539
+ padding: 0.25rem 0.5rem;
540
+ }
541
+ .cv-workspace-chip--on { background: rgb(229 231 235); }
542
+ .dark .cv-workspace-chip--on { background: rgb(51 65 85); }
543
+
544
+ /* A cor do próprio rótulo é o estado da janela; selecionado, o mesmo tom vira o fundo. */
545
+ .cv-workspace-chip--fresh { color: rgb(22 163 74); }
546
+ .cv-workspace-chip--warning { color: rgb(202 138 4); }
547
+ .cv-workspace-chip--critical { color: rgb(220 38 38); }
548
+ .cv-workspace-chip--expired { color: rgb(107 114 128); }
549
+ .cv-workspace-chip--fresh.cv-workspace-chip--on { background: rgb(220 252 231); }
550
+ .cv-workspace-chip--warning.cv-workspace-chip--on { background: rgb(254 249 195); }
551
+ .cv-workspace-chip--critical.cv-workspace-chip--on { background: rgb(254 226 226); }
552
+ .cv-workspace-chip--expired.cv-workspace-chip--on { background: rgb(229 231 235); }
553
+ .dark .cv-workspace-chip--fresh { color: rgb(74 222 128); }
554
+ .dark .cv-workspace-chip--warning { color: rgb(250 204 21); }
555
+ .dark .cv-workspace-chip--critical { color: rgb(248 113 113); }
556
+ .dark .cv-workspace-chip--expired { color: rgb(148 163 184); }
557
+ .dark .cv-workspace-chip--fresh.cv-workspace-chip--on { background: rgb(20 83 45); }
558
+ .dark .cv-workspace-chip--warning.cv-workspace-chip--on { background: rgb(113 63 18); }
559
+ .dark .cv-workspace-chip--critical.cv-workspace-chip--on { background: rgb(127 29 29); }
560
+ .dark .cv-workspace-chip--expired.cv-workspace-chip--on { background: rgb(51 65 85); }
561
+
562
+ .cv-workspace-selectall {
563
+ display: flex;
564
+ align-items: center;
565
+ gap: 0.5rem;
566
+ font-size: 0.75rem;
567
+ }
568
+
569
+ .cv-workspace-rows { flex: 1; min-height: 0; overflow-y: auto; }
570
+
571
+ .cv-workspace-empty { padding: 1rem; font-size: 0.875rem; color: rgb(107 114 128); }
572
+
573
+ .cv-workspace-bulk {
574
+ display: flex;
575
+ flex-wrap: wrap;
576
+ align-items: center;
577
+ justify-content: space-between;
578
+ gap: 0.5rem;
579
+ padding: 0.5rem 0.75rem;
580
+ border-bottom: 1px solid rgb(191 219 254);
581
+ background: rgb(239 246 255);
582
+ font-size: 0.75rem;
583
+ }
584
+ .dark .cv-workspace-bulk { background: rgb(23 37 84); border-color: rgb(30 58 138); }
585
+ .cv-workspace-bulk__count { font-weight: 500; color: rgb(29 78 216); }
586
+ .dark .cv-workspace-bulk__count { color: rgb(147 197 253); }
587
+ .cv-workspace-bulk__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
588
+ .cv-workspace-bulk__actions button {
589
+ border: 1px solid rgb(191 219 254);
590
+ border-radius: 0.375rem;
591
+ padding: 0.25rem 0.5rem;
592
+ }
593
+ .cv-workspace-bulk__actions button:disabled { opacity: 0.5; }
594
+
595
+ .cv-workspace-pager {
596
+ display: flex;
597
+ align-items: center;
598
+ justify-content: space-between;
599
+ gap: 0.5rem;
600
+ border-top: 1px solid rgb(229 231 235);
601
+ padding: 0.5rem 0.75rem;
602
+ font-size: 0.75rem;
603
+ color: rgb(107 114 128);
604
+ }
605
+ .dark .cv-workspace-pager { border-color: rgb(51 65 85); }
606
+ .cv-workspace-pager__buttons { display: flex; align-items: center; gap: 0.25rem; }
607
+ .cv-workspace-pager__buttons button { padding: 0 0.5rem; }
608
+ .cv-workspace-pager__buttons button:disabled { opacity: 0.4; }
609
+
610
+ /* Modal de template do envio em lote. Sobre a tela inteira e não dentro da coluna da lista: a
611
+ escolha vale para todas as conversas marcadas, e ancorado na lista parecia filtro dela. */
612
+ .cv-workspace-modal {
613
+ position: fixed;
614
+ inset: 0;
615
+ z-index: 50;
616
+ display: flex;
617
+ align-items: center;
618
+ justify-content: center;
619
+ padding: 1rem;
620
+ background: rgb(0 0 0 / 50%);
621
+ }
622
+
623
+ .cv-workspace-modal__box {
624
+ display: flex;
625
+ width: 100%;
626
+ max-width: 28rem;
627
+ max-height: 80vh;
628
+ flex-direction: column;
629
+ overflow: hidden;
630
+ border-radius: 0.75rem;
631
+ border: 1px solid #e5e7eb;
632
+ background: #fff;
633
+ box-shadow: 0 20px 25px -5px rgb(0 0 0 / 25%);
634
+ }
635
+
636
+ .cv-workspace-modal__header {
637
+ display: flex;
638
+ align-items: flex-start;
639
+ justify-content: space-between;
640
+ gap: 0.75rem;
641
+ border-bottom: 1px solid #e5e7eb;
642
+ padding: 1rem 1.25rem;
643
+ }
644
+
645
+ .cv-workspace-modal__header h3 {
646
+ font-weight: 600;
647
+ }
648
+
649
+ .cv-workspace-modal__header p {
650
+ margin-top: 0.125rem;
651
+ font-size: 0.75rem;
652
+ color: #6b7280;
653
+ }
654
+
655
+ .cv-workspace-modal__search {
656
+ border-bottom: 1px solid #f3f4f6;
657
+ padding: 0.75rem 1rem;
658
+ }
659
+
660
+ .cv-workspace-modal__search input {
661
+ width: 100%;
662
+ border-radius: 0.5rem;
663
+ border: 1px solid #e5e7eb;
664
+ padding: 0.5rem 0.75rem;
665
+ font-size: 0.875rem;
666
+ }
667
+
668
+ .cv-workspace-modal__list {
669
+ flex: 1;
670
+ overflow-y: auto;
671
+ padding: 0.5rem;
672
+ }
673
+
674
+ .cv-workspace-modal__item {
675
+ display: flex;
676
+ width: 100%;
677
+ flex-direction: column;
678
+ gap: 0.125rem;
679
+ border: 1px solid transparent;
680
+ border-radius: 0.5rem;
681
+ padding: 0.625rem 0.75rem;
682
+ text-align: left;
683
+ font-size: 0.875rem;
684
+ }
685
+
686
+ .cv-workspace-modal__item:hover {
687
+ background: #f9fafb;
688
+ }
689
+
690
+ .cv-workspace-modal__item--on {
691
+ border-color: #bfdbfe;
692
+ background: #eff6ff;
693
+ color: #1d4ed8;
694
+ }
695
+
696
+ .cv-workspace-modal__item-name {
697
+ overflow: hidden;
698
+ text-overflow: ellipsis;
699
+ white-space: nowrap;
700
+ font-weight: 500;
701
+ }
702
+
703
+ .cv-workspace-modal__item-meta {
704
+ font-size: 0.75rem;
705
+ color: #9ca3af;
706
+ }
707
+
708
+ .cv-workspace-modal__warning {
709
+ border-top: 1px solid #fde68a;
710
+ background: #fffbeb;
711
+ padding: 0.5rem 1rem;
712
+ font-size: 0.75rem;
713
+ color: #b45309;
714
+ }
715
+
716
+ .cv-workspace-modal__footer {
717
+ display: flex;
718
+ justify-content: flex-end;
719
+ gap: 0.5rem;
720
+ border-top: 1px solid #e5e7eb;
721
+ padding: 0.75rem 1rem;
722
+ }
723
+
724
+ .cv-workspace-modal__footer button {
725
+ min-height: 2.75rem;
726
+ border-radius: 0.5rem;
727
+ border: 1px solid #e5e7eb;
728
+ padding: 0 0.875rem;
729
+ font-size: 0.875rem;
730
+ }
731
+
732
+ .cv-workspace-modal__footer button:last-child {
733
+ border-color: transparent;
734
+ background: #2563eb;
735
+ color: #fff;
736
+ }
737
+
738
+ .cv-workspace-modal__footer button:disabled {
739
+ opacity: 0.5;
740
+ }
741
+
742
+ .dark .cv-workspace-modal__box {
743
+ border-color: #374151;
744
+ background: #1f2937;
745
+ }
746
+
747
+ .dark .cv-workspace-modal__header,
748
+ .dark .cv-workspace-modal__footer {
749
+ border-color: #374151;
750
+ }
751
+
752
+ .dark .cv-workspace-modal__search {
753
+ border-color: #374151;
754
+ }
755
+
756
+ .dark .cv-workspace-modal__search input {
757
+ border-color: #4b5563;
758
+ background: #374151;
759
+ color: #f3f4f6;
760
+ }
761
+
762
+ .dark .cv-workspace-modal__item:hover {
763
+ background: rgb(55 65 81 / 50%);
764
+ }
765
+
766
+ .dark .cv-workspace-modal__item--on {
767
+ border-color: #1e40af;
768
+ background: rgb(23 37 84 / 40%);
769
+ color: #93c5fd;
770
+ }
771
+
772
+ .dark .cv-workspace-modal__warning {
773
+ border-color: #92400e;
774
+ background: rgb(69 26 3 / 40%);
775
+ color: #fbbf24;
776
+ }
777
+
778
+ .dark .cv-workspace-modal__footer button {
779
+ border-color: #4b5563;
780
+ color: #f3f4f6;
781
+ }
782
+
783
+ /* Fila de anexos acima da barra: nomes visíveis para conferir antes de mandar, e um X por item —
784
+ escolher seis arquivos e não poder tirar o errado obrigava a recomeçar. */
785
+ .cv-workspace-attachments {
786
+ display: flex;
787
+ flex-wrap: wrap;
788
+ gap: 0.5rem;
789
+ margin: 0 0 0.5rem;
790
+ padding: 0;
791
+ list-style: none;
792
+ }
793
+ .cv-workspace-attachments li {
794
+ display: flex;
795
+ align-items: center;
796
+ gap: 0.5rem;
797
+ max-width: 14rem;
798
+ padding: 0.25rem 0.5rem;
799
+ border: 1px solid rgb(226 232 240);
800
+ border-radius: 0.5rem;
801
+ font-size: 0.75rem;
802
+ }
803
+ .cv-workspace-attachments li span {
804
+ overflow: hidden;
805
+ text-overflow: ellipsis;
806
+ white-space: nowrap;
807
+ }
808
+ .cv-workspace-attachments li button {
809
+ flex: none;
810
+ min-width: 1.5rem;
811
+ min-height: 1.5rem;
812
+ cursor: pointer;
813
+ background: none;
814
+ border: 0;
815
+ color: inherit;
816
+ }
817
+ .dark .cv-workspace-attachments li {
818
+ border-color: rgb(51 65 85);
819
+ }
820
+
821
+ /* Peças de listagem (documentos, mensagens): tabela com filtros, seleção em lote e paginação. */
822
+ .cv-filter-count {
823
+ display: inline-flex;
824
+ align-items: center;
825
+ justify-content: center;
826
+ min-width: 1rem;
827
+ height: 1rem;
828
+ padding: 0 0.25rem;
829
+ border-radius: 9999px;
830
+ background: rgb(37 99 235);
831
+ color: white;
832
+ font-size: 0.625rem;
833
+ font-weight: 600;
834
+ }
835
+ .cv-filter-menu {
836
+ position: absolute;
837
+ top: 100%;
838
+ left: 0;
839
+ z-index: 20;
840
+ margin-top: 0.25rem;
841
+ min-width: 12rem;
842
+ padding: 0.5rem;
843
+ border: 1px solid rgb(226 232 240);
844
+ border-radius: 0.5rem;
845
+ background: white;
846
+ box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1);
847
+ }
848
+ .dark .cv-filter-menu { background: rgb(30 41 59); border-color: rgb(71 85 105); }
849
+ .cv-filter-option {
850
+ display: flex;
851
+ align-items: center;
852
+ gap: 0.5rem;
853
+ padding: 0.375rem 0.5rem;
854
+ border-radius: 0.375rem;
855
+ font-size: 0.75rem;
856
+ cursor: pointer;
857
+ }
858
+ .cv-filter-option:hover { background: rgb(241 245 249); }
859
+ .dark .cv-filter-option:hover { background: rgb(51 65 85); }
860
+ .cv-bulk-bar {
861
+ display: flex;
862
+ flex-wrap: wrap;
863
+ align-items: center;
864
+ gap: 0.5rem;
865
+ padding: 0.5rem 0.75rem;
866
+ border: 1px solid rgb(191 219 254);
867
+ border-radius: 0.5rem;
868
+ background: rgb(239 246 255);
869
+ }
870
+ .dark .cv-bulk-bar { background: rgb(30 58 138 / 0.25); border-color: rgb(30 64 175); }
871
+ .cv-listing-pagination {
872
+ display: flex;
873
+ flex-wrap: wrap;
874
+ align-items: center;
875
+ justify-content: space-between;
876
+ gap: 0.5rem;
877
+ padding-top: 0.5rem;
878
+ border-top: 1px solid rgb(241 245 249);
879
+ }
880
+ .dark .cv-listing-pagination { border-color: rgb(30 41 59); }
881
+ .cv-listing-perpage {
882
+ height: 2rem;
883
+ padding: 0 0.5rem;
884
+ border: 1px solid rgb(226 232 240);
885
+ border-radius: 0.375rem;
886
+ background: transparent;
887
+ font-size: 0.75rem;
888
+ }
889
+ .dark .cv-listing-perpage { border-color: rgb(71 85 105); }
890
+
891
+ /**
892
+ * Cor padrão de borda para as classes `border` sem cor ao lado.
893
+ *
894
+ * O Tailwind v4 trocou o padrão de `gray-200` por `currentColor`, e os componentes daqui foram
895
+ * escritos no v3. Em produto que traz a base do shadcn nada aparece — ela já redefine isto; em
896
+ * produto sem shadcn, cada `border` sai na cor do texto, e a tabela de documentos vinha com régua
897
+ * azul-quase-preta em vez de cinza. `:where()` zera a especificidade do seletor, então qualquer
898
+ * `border-*` do host ou daqui continua ganhando por especificidade — sem depender da camada
899
+ * `base` do Tailwind, que quebra o build de host que importa este arquivo fora do pipeline do
900
+ * Tailwind (erro do postcss: "`@layer base` is used but no matching `@tailwind base` directive").
901
+ */
902
+ :root { --cv-border-color: rgb(229 231 235); }
903
+ .dark { --cv-border-color: rgb(51 65 85); }
904
+
905
+ :where(*, ::before, ::after, ::backdrop, ::file-selector-button) {
906
+ border-color: var(--cv-border-color);
907
+ }
908
+
909
+ /* Tabela de listagem: a moldura, o cabeçalho e a zebra que `web.md` §7 exige, no stylesheet pelo
910
+ mesmo motivo do resto — host que não varre `node_modules` com `@source` não compila utilitário
911
+ nenhum do pacote, e a tabela sairia crua. */
912
+ .cv-table-card {
913
+ overflow-x: auto;
914
+ border: 1px solid rgb(229 231 235);
915
+ border-radius: 0.75rem;
916
+ background: #fff;
917
+ }
918
+ .dark .cv-table-card { border-color: rgb(51 65 85); background: rgb(17 24 39); }
919
+
920
+ /* `collapse` porque a régua de baixo mora no `tr`: com o `separate` padrão o navegador ignora borda
921
+ de linha e a tabela ficava sem separação nenhuma entre os registros. */
922
+ .cv-table {
923
+ width: 100%;
924
+ border-collapse: collapse;
925
+ font-size: 0.875rem;
926
+ }
927
+
928
+ .cv-table thead {
929
+ background: rgb(248 250 252);
930
+ color: rgb(100 116 139);
931
+ }
932
+ .dark .cv-table thead { background: rgb(30 41 59 / 60%); color: rgb(148 163 184); }
933
+
934
+ .cv-table thead th {
935
+ border-bottom: 1px solid rgb(226 232 240);
936
+ white-space: nowrap;
937
+ }
938
+ .dark .cv-table thead th { border-bottom-color: rgb(51 65 85); }
939
+
940
+ .cv-table tbody tr { border-bottom: 1px solid rgb(241 245 249); }
941
+ .dark .cv-table tbody tr { border-bottom-color: rgb(30 41 59); }
942
+ .cv-table tbody tr:last-child { border-bottom: 0; }
943
+
944
+ /* A alternada é o que leva o olho do nome do arquivo até a coluna de ações; em tela larga a régua
945
+ sozinha não segura a linha. */
946
+ .cv-table tbody tr:nth-child(even) { background: rgb(248 250 252 / 70%); }
947
+ .dark .cv-table tbody tr:nth-child(even) { background: rgb(30 41 59 / 35%); }
948
+
949
+ .cv-table tbody tr:hover { background: rgb(239 246 255); }
950
+ .dark .cv-table tbody tr:hover { background: rgb(30 58 138 / 25%); }
951
+
952
+ /* Extensão do arquivo como etiqueta: `PDF` e `DOCX` têm larguras parecidas e a coluna para de dançar
953
+ a cada linha, o que o MIME cru não permitia. */
954
+ .cv-type-tag {
955
+ display: inline-block;
956
+ border-radius: 0.25rem;
957
+ background: rgb(241 245 249);
958
+ padding: 0.125rem 0.375rem;
959
+ font-size: 0.6875rem;
960
+ font-weight: 600;
961
+ letter-spacing: 0.02em;
962
+ color: rgb(71 85 105);
963
+ }
964
+ .dark .cv-type-tag { background: rgb(51 65 85); color: rgb(203 213 225); }
965
+
966
+ /* Dica de ação (ver `Tooltip.tsx`). Impressa em `document.body`, então a posição é da janela e o
967
+ `z-index` fica acima de qualquer painel do produto. */
968
+ .cv-tooltip {
969
+ position: fixed;
970
+ z-index: 9999;
971
+ max-width: min(16rem, 90vw);
972
+ transform: translate(-50%, -100%);
973
+ border-radius: 0.375rem;
974
+ background: rgb(17 24 39 / 95%);
975
+ padding: 0.3125rem 0.5rem;
976
+ font-size: 0.75rem;
977
+ line-height: 1.2;
978
+ color: #fff;
979
+ text-align: center;
980
+ box-shadow: 0 4px 12px rgb(0 0 0 / 18%);
981
+ pointer-events: none;
982
+ animation: cv-tooltip-in 90ms ease-out;
983
+ }
984
+
985
+ .cv-tooltip--bottom {
986
+ transform: translate(-50%, 0);
987
+ }
988
+
989
+ .dark .cv-tooltip {
990
+ background: rgb(243 244 246 / 96%);
991
+ color: rgb(17 24 39);
992
+ }
993
+
994
+ @keyframes cv-tooltip-in {
995
+ from { opacity: 0; }
996
+ to { opacity: 1; }
997
+ }
998
+
999
+ @media (prefers-reduced-motion: reduce) {
1000
+ .cv-tooltip { animation: none; }
1001
+ }
1002
+
1003
+ /* Barra de composição: fundo neutro para separar da conversa e para os atalhos e o campo de texto
1004
+ terem contraste próprio. Sobre branco, régua branca e campo cinza-claro se confundiam num bloco
1005
+ só, sem hierarquia. */
1006
+ .cv-composer-bar {
1007
+ border-top: 1px solid rgb(229 231 235);
1008
+ background: rgb(240 242 245);
1009
+ padding: 0.625rem 0.75rem;
1010
+ }
1011
+
1012
+ .dark .cv-composer-bar {
1013
+ border-top-color: rgb(51 65 85);
1014
+ background: rgb(17 24 39);
1015
+ }