@vertesia/ui 1.6.0-dev.20261004.085740Z → 1.6.0-dev.20261009.095813Z

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 (235) hide show
  1. package/README.md +24 -0
  2. package/lib/boot/vite.d.ts +3 -0
  3. package/lib/boot/vite.d.ts.map +1 -1
  4. package/lib/boot/vite.js +12 -0
  5. package/lib/boot/vite.js.map +1 -1
  6. package/lib/core/components/shadcn/button.d.ts +1 -0
  7. package/lib/core/components/shadcn/button.d.ts.map +1 -1
  8. package/lib/core/components/shadcn/button.js +2 -2
  9. package/lib/core/components/shadcn/button.js.map +1 -1
  10. package/lib/core/components/shadcn/selectBox.d.ts.map +1 -1
  11. package/lib/core/components/shadcn/selectBox.js +2 -2
  12. package/lib/core/components/shadcn/selectBox.js.map +1 -1
  13. package/lib/core/components/shadcn/tabs.d.ts +2 -1
  14. package/lib/core/components/shadcn/tabs.d.ts.map +1 -1
  15. package/lib/core/components/shadcn/tabs.js +6 -4
  16. package/lib/core/components/shadcn/tabs.js.map +1 -1
  17. package/lib/env/index.d.ts +9 -1
  18. package/lib/env/index.d.ts.map +1 -1
  19. package/lib/env/index.js +1 -1
  20. package/lib/env/index.js.map +1 -1
  21. package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts +1 -1
  22. package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
  23. package/lib/features/agent/chat/AgentRequestInputOverlay.js +16 -10
  24. package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
  25. package/lib/features/agent/chat/AskUserWidget.d.ts +7 -1
  26. package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
  27. package/lib/features/agent/chat/AskUserWidget.js +17 -16
  28. package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
  29. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  30. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +2 -253
  31. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  32. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts +1 -3
  33. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.d.ts.map +1 -1
  34. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js +2 -8
  35. package/lib/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.js.map +1 -1
  36. package/lib/features/agent/chat/ModernAgentOutput/agentMarkdownStyles.d.ts +4 -0
  37. package/lib/features/agent/chat/ModernAgentOutput/agentMarkdownStyles.d.ts.map +1 -0
  38. package/lib/features/agent/chat/ModernAgentOutput/agentMarkdownStyles.js +248 -0
  39. package/lib/features/agent/chat/ModernAgentOutput/agentMarkdownStyles.js.map +1 -0
  40. package/lib/features/media-viewer/ImagePanel.d.ts +1 -1
  41. package/lib/features/media-viewer/ImagePanel.d.ts.map +1 -1
  42. package/lib/features/media-viewer/ImagePanel.js +40 -10
  43. package/lib/features/media-viewer/ImagePanel.js.map +1 -1
  44. package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -1
  45. package/lib/features/store/types/IntakePolicyEditor.js +1 -1
  46. package/lib/features/store/types/IntakePolicyEditor.js.map +1 -1
  47. package/lib/i18n/locales/ar.json +15 -0
  48. package/lib/i18n/locales/de.json +15 -0
  49. package/lib/i18n/locales/en.json +15 -0
  50. package/lib/i18n/locales/es.json +15 -0
  51. package/lib/i18n/locales/fr.json +15 -0
  52. package/lib/i18n/locales/it.json +15 -0
  53. package/lib/i18n/locales/ja.json +15 -0
  54. package/lib/i18n/locales/ko.json +15 -0
  55. package/lib/i18n/locales/pt.json +15 -0
  56. package/lib/i18n/locales/ru.json +15 -0
  57. package/lib/i18n/locales/tr.json +15 -0
  58. package/lib/i18n/locales/zh-TW.json +15 -0
  59. package/lib/i18n/locales/zh.json +15 -0
  60. package/lib/session/auth/composable.d.ts +1 -5
  61. package/lib/session/auth/composable.d.ts.map +1 -1
  62. package/lib/session/auth/composable.js +1 -10
  63. package/lib/session/auth/composable.js.map +1 -1
  64. package/lib/session/auth/firebase.d.ts.map +1 -1
  65. package/lib/session/auth/firebase.js +8 -5
  66. package/lib/session/auth/firebase.js.map +1 -1
  67. package/lib/session/auth/oauth.d.ts.map +1 -1
  68. package/lib/session/auth/oauth.js +43 -17
  69. package/lib/session/auth/oauth.js.map +1 -1
  70. package/lib/session/auth/vertesiaHosts.d.ts +0 -40
  71. package/lib/session/auth/vertesiaHosts.d.ts.map +1 -1
  72. package/lib/session/auth/vertesiaHosts.js +2 -45
  73. package/lib/session/auth/vertesiaHosts.js.map +1 -1
  74. package/lib/session/index.d.ts +1 -1
  75. package/lib/session/index.d.ts.map +1 -1
  76. package/lib/session/index.js +1 -1
  77. package/lib/session/index.js.map +1 -1
  78. package/lib/session/scopeSelection.d.ts +4 -0
  79. package/lib/session/scopeSelection.d.ts.map +1 -1
  80. package/lib/session/scopeSelection.js +11 -0
  81. package/lib/session/scopeSelection.js.map +1 -1
  82. package/lib/shell/AuthScreenPreview.d.ts.map +1 -1
  83. package/lib/shell/AuthScreenPreview.js +1 -0
  84. package/lib/shell/AuthScreenPreview.js.map +1 -1
  85. package/lib/shell/login/SignInFlow.d.ts +3 -1
  86. package/lib/shell/login/SignInFlow.d.ts.map +1 -1
  87. package/lib/shell/login/SignInFlow.js +13 -4
  88. package/lib/shell/login/SignInFlow.js.map +1 -1
  89. package/lib/shell/login/SignInIcons.d.ts.map +1 -1
  90. package/lib/shell/login/SignInIcons.js +2 -1
  91. package/lib/shell/login/SignInIcons.js.map +1 -1
  92. package/lib/shell/login/SignInPasswordStep.d.ts +9 -0
  93. package/lib/shell/login/SignInPasswordStep.d.ts.map +1 -0
  94. package/lib/shell/login/SignInPasswordStep.js +58 -0
  95. package/lib/shell/login/SignInPasswordStep.js.map +1 -0
  96. package/lib/shell/login/SignInPrimitives.d.ts +13 -0
  97. package/lib/shell/login/SignInPrimitives.d.ts.map +1 -1
  98. package/lib/shell/login/SignInPrimitives.js +11 -1
  99. package/lib/shell/login/SignInPrimitives.js.map +1 -1
  100. package/lib/shell/login/SignInProvidersStep.d.ts +3 -1
  101. package/lib/shell/login/SignInProvidersStep.d.ts.map +1 -1
  102. package/lib/shell/login/SignInProvidersStep.js +4 -2
  103. package/lib/shell/login/SignInProvidersStep.js.map +1 -1
  104. package/lib/shell/login/SignInReturningStep.d.ts +3 -1
  105. package/lib/shell/login/SignInReturningStep.d.ts.map +1 -1
  106. package/lib/shell/login/SignInReturningStep.js +18 -8
  107. package/lib/shell/login/SignInReturningStep.js.map +1 -1
  108. package/lib/shell/login/SignInTenantStep.d.ts +3 -1
  109. package/lib/shell/login/SignInTenantStep.d.ts.map +1 -1
  110. package/lib/shell/login/SignInTenantStep.js +2 -2
  111. package/lib/shell/login/SignInTenantStep.js.map +1 -1
  112. package/lib/shell/login/SignInWithProviderButton.d.ts +5 -3
  113. package/lib/shell/login/SignInWithProviderButton.d.ts.map +1 -1
  114. package/lib/shell/login/SignInWithProviderButton.js +8 -7
  115. package/lib/shell/login/SignInWithProviderButton.js.map +1 -1
  116. package/lib/shell/login/SigninScreen.d.ts.map +1 -1
  117. package/lib/shell/login/SigninScreen.js +9 -3
  118. package/lib/shell/login/SigninScreen.js.map +1 -1
  119. package/lib/shell/login/signInUtils.d.ts +24 -4
  120. package/lib/shell/login/signInUtils.d.ts.map +1 -1
  121. package/lib/shell/login/signInUtils.js +53 -1
  122. package/lib/shell/login/signInUtils.js.map +1 -1
  123. package/lib/vertesia-ui-boot.js.map +1 -1
  124. package/lib/vertesia-ui-core.js +42 -42
  125. package/lib/vertesia-ui-core.js.map +1 -1
  126. package/lib/vertesia-ui-env.js +1 -1
  127. package/lib/vertesia-ui-env.js.map +1 -1
  128. package/lib/vertesia-ui-features.js +574 -589
  129. package/lib/vertesia-ui-features.js.map +1 -1
  130. package/lib/vertesia-ui-i18n.1NWiB6fw.chunk.js +5 -0
  131. package/lib/vertesia-ui-i18n.1NWiB6fw.chunk.js.map +1 -0
  132. package/lib/vertesia-ui-i18n.6Ozlf6Ks.chunk.js +5 -0
  133. package/lib/vertesia-ui-i18n.6Ozlf6Ks.chunk.js.map +1 -0
  134. package/lib/vertesia-ui-i18n.AttJpg8U.chunk.js +5 -0
  135. package/lib/vertesia-ui-i18n.AttJpg8U.chunk.js.map +1 -0
  136. package/lib/vertesia-ui-i18n.BI_xdp49.chunk.js +5 -0
  137. package/lib/vertesia-ui-i18n.BI_xdp49.chunk.js.map +1 -0
  138. package/lib/vertesia-ui-i18n.C-2EEX6w.chunk.js +5 -0
  139. package/lib/vertesia-ui-i18n.C-2EEX6w.chunk.js.map +1 -0
  140. package/lib/vertesia-ui-i18n.CAmo54FO.chunk.js +5 -0
  141. package/lib/vertesia-ui-i18n.CAmo54FO.chunk.js.map +1 -0
  142. package/lib/vertesia-ui-i18n.CbBzmHNP.chunk.js +5 -0
  143. package/lib/vertesia-ui-i18n.CbBzmHNP.chunk.js.map +1 -0
  144. package/lib/vertesia-ui-i18n.DZgTzkIg.chunk.js +5 -0
  145. package/lib/vertesia-ui-i18n.DZgTzkIg.chunk.js.map +1 -0
  146. package/lib/vertesia-ui-i18n.DZsITxq5.chunk.js +5 -0
  147. package/lib/vertesia-ui-i18n.DZsITxq5.chunk.js.map +1 -0
  148. package/lib/vertesia-ui-i18n.Dbf2GHth.chunk.js +5 -0
  149. package/lib/vertesia-ui-i18n.Dbf2GHth.chunk.js.map +1 -0
  150. package/lib/vertesia-ui-i18n.js +2 -2
  151. package/lib/vertesia-ui-i18n.js.map +1 -1
  152. package/lib/vertesia-ui-i18n.lleWnH5n.chunk.js +5 -0
  153. package/lib/vertesia-ui-i18n.lleWnH5n.chunk.js.map +1 -0
  154. package/lib/vertesia-ui-i18n.wG_XSkbr.chunk.js +5 -0
  155. package/lib/vertesia-ui-i18n.wG_XSkbr.chunk.js.map +1 -0
  156. package/lib/vertesia-ui-layout.js +15 -15
  157. package/lib/vertesia-ui-layout.js.map +1 -1
  158. package/lib/vertesia-ui-rich-text.js +40 -40
  159. package/lib/vertesia-ui-rich-text.js.map +1 -1
  160. package/lib/vertesia-ui-router.js.map +1 -1
  161. package/lib/vertesia-ui-session.js +1 -1
  162. package/lib/vertesia-ui-session.js.map +1 -1
  163. package/lib/vertesia-ui-shell.js +54 -47
  164. package/lib/vertesia-ui-shell.js.map +1 -1
  165. package/lib/vertesia-ui-widgets.js +47 -47
  166. package/lib/vertesia-ui-widgets.js.map +1 -1
  167. package/package.json +20 -20
  168. package/src/boot/vite.ts +15 -0
  169. package/src/core/components/shadcn/button.tsx +3 -2
  170. package/src/core/components/shadcn/selectBox.tsx +12 -4
  171. package/src/core/components/shadcn/tabs.tsx +9 -3
  172. package/src/css/index.css +1 -1
  173. package/src/css/typography.css +111 -88
  174. package/src/env/index.ts +10 -3
  175. package/src/features/agent/chat/AgentRequestInputOverlay.tsx +73 -34
  176. package/src/features/agent/chat/AskUserWidget.tsx +225 -206
  177. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +2 -253
  178. package/src/features/agent/chat/ModernAgentOutput/CollapsibleAgentMarkdown.tsx +2 -8
  179. package/src/features/agent/chat/ModernAgentOutput/agentMarkdownStyles.ts +248 -0
  180. package/src/features/media-viewer/ImagePanel.tsx +51 -10
  181. package/src/features/store/types/IntakePolicyEditor.tsx +2 -1
  182. package/src/i18n/locales/ar.json +15 -0
  183. package/src/i18n/locales/de.json +15 -0
  184. package/src/i18n/locales/en.json +15 -0
  185. package/src/i18n/locales/es.json +15 -0
  186. package/src/i18n/locales/fr.json +15 -0
  187. package/src/i18n/locales/it.json +15 -0
  188. package/src/i18n/locales/ja.json +15 -0
  189. package/src/i18n/locales/ko.json +15 -0
  190. package/src/i18n/locales/pt.json +15 -0
  191. package/src/i18n/locales/ru.json +15 -0
  192. package/src/i18n/locales/tr.json +15 -0
  193. package/src/i18n/locales/zh-TW.json +15 -0
  194. package/src/i18n/locales/zh.json +15 -0
  195. package/src/session/auth/composable.ts +1 -11
  196. package/src/session/auth/firebase.ts +9 -6
  197. package/src/session/auth/oauth.ts +47 -16
  198. package/src/session/auth/vertesiaHosts.ts +2 -47
  199. package/src/session/index.ts +1 -1
  200. package/src/session/scopeSelection.ts +13 -0
  201. package/src/shell/AuthScreenPreview.tsx +1 -0
  202. package/src/shell/login/SignInFlow.tsx +23 -2
  203. package/src/shell/login/SignInIcons.tsx +2 -1
  204. package/src/shell/login/SignInPasswordStep.tsx +103 -0
  205. package/src/shell/login/SignInPrimitives.tsx +53 -1
  206. package/src/shell/login/SignInProvidersStep.tsx +8 -4
  207. package/src/shell/login/SignInReturningStep.tsx +20 -8
  208. package/src/shell/login/SignInTenantStep.tsx +6 -2
  209. package/src/shell/login/SignInWithProviderButton.tsx +11 -7
  210. package/src/shell/login/SigninScreen.tsx +8 -3
  211. package/src/shell/login/signInUtils.ts +68 -8
  212. package/lib/vertesia-ui-i18n.BCPusS2_.chunk.js +0 -5
  213. package/lib/vertesia-ui-i18n.BCPusS2_.chunk.js.map +0 -1
  214. package/lib/vertesia-ui-i18n.BHWlHchf.chunk.js +0 -5
  215. package/lib/vertesia-ui-i18n.BHWlHchf.chunk.js.map +0 -1
  216. package/lib/vertesia-ui-i18n.BkNx8SZu.chunk.js +0 -5
  217. package/lib/vertesia-ui-i18n.BkNx8SZu.chunk.js.map +0 -1
  218. package/lib/vertesia-ui-i18n.C1LasLrO.chunk.js +0 -5
  219. package/lib/vertesia-ui-i18n.C1LasLrO.chunk.js.map +0 -1
  220. package/lib/vertesia-ui-i18n.D8PQ5yKU.chunk.js +0 -5
  221. package/lib/vertesia-ui-i18n.D8PQ5yKU.chunk.js.map +0 -1
  222. package/lib/vertesia-ui-i18n.DUtVV1Bq.chunk.js +0 -5
  223. package/lib/vertesia-ui-i18n.DUtVV1Bq.chunk.js.map +0 -1
  224. package/lib/vertesia-ui-i18n.DgA36_k5.chunk.js +0 -5
  225. package/lib/vertesia-ui-i18n.DgA36_k5.chunk.js.map +0 -1
  226. package/lib/vertesia-ui-i18n.DmG-fjjZ.chunk.js +0 -5
  227. package/lib/vertesia-ui-i18n.DmG-fjjZ.chunk.js.map +0 -1
  228. package/lib/vertesia-ui-i18n.DreWvQIk.chunk.js +0 -5
  229. package/lib/vertesia-ui-i18n.DreWvQIk.chunk.js.map +0 -1
  230. package/lib/vertesia-ui-i18n.Pp8Tj48d.chunk.js +0 -5
  231. package/lib/vertesia-ui-i18n.Pp8Tj48d.chunk.js.map +0 -1
  232. package/lib/vertesia-ui-i18n.gais--x5.chunk.js +0 -5
  233. package/lib/vertesia-ui-i18n.gais--x5.chunk.js.map +0 -1
  234. package/lib/vertesia-ui-i18n.xkqaKpY_.chunk.js +0 -5
  235. package/lib/vertesia-ui-i18n.xkqaKpY_.chunk.js.map +0 -1
@@ -43,6 +43,7 @@ import {
43
43
  } from '../workstreams.js';
44
44
  import { createAgentMarkdownAnchor } from './AgentMarkdownAnchor';
45
45
  import { AttachmentPreviewList, parseUserMessageAttachments } from './AttachmentPreview';
46
+ import { agentMarkdownStyles } from './agentMarkdownStyles.js';
46
47
  import BatchProgressPanel, { type BatchProgressPanelClassNames } from './BatchProgressPanel';
47
48
  import {
48
49
  AGENT_LINE_CLAMP_CLASS,
@@ -3118,259 +3119,7 @@ function AllMessagesMixedComponent({
3118
3119
  data-view-mode={viewMode}
3119
3120
  >
3120
3121
  {/* Global styles for vprose markdown content */}
3121
- <style>{`
3122
- /* Better vertical rhythm for markdown */
3123
- .vprose > * + * {
3124
- margin-top: 0.625rem;
3125
- }
3126
- .vprose > h1 + *,
3127
- .vprose > h2 + *,
3128
- .vprose > h3 + * {
3129
- margin-top: 0.375rem;
3130
- }
3131
- /* Tables should read like part of the conversation, not a separate app grid. */
3132
- .vprose table {
3133
- margin-top: 0.875rem;
3134
- margin-bottom: 0.875rem;
3135
- border-collapse: collapse;
3136
- width: 100%;
3137
- background: transparent;
3138
- }
3139
- .vprose th,
3140
- .vprose td {
3141
- padding: 0.5rem 0.625rem;
3142
- border: 0;
3143
- border-bottom: 1px solid color-mix(in oklch, var(--border) 70%, transparent);
3144
- background: transparent;
3145
- text-align: left;
3146
- }
3147
- .vprose thead th {
3148
- background: transparent;
3149
- font-weight: 600;
3150
- color: var(--muted);
3151
- font-size: 0.75rem;
3152
- text-transform: none;
3153
- letter-spacing: 0;
3154
- }
3155
- .vprose tbody tr:hover {
3156
- background: transparent;
3157
- }
3158
- /* Dark mode table styles */
3159
- .dark .vprose th,
3160
- .dark .vprose td {
3161
- border-color: color-mix(in oklch, var(--border) 70%, transparent);
3162
- }
3163
- .dark .vprose thead th {
3164
- background: transparent;
3165
- color: var(--muted);
3166
- }
3167
- .dark .vprose tbody tr:hover {
3168
- background: transparent;
3169
- }
3170
- /* Horizontal rules as section dividers */
3171
- .vprose hr {
3172
- margin-top: 1rem;
3173
- margin-bottom: 1rem;
3174
- border-color: var(--border);
3175
- }
3176
- /* Better blockquote styling */
3177
- .vprose blockquote {
3178
- margin-top: 0.875rem;
3179
- margin-bottom: 0.875rem;
3180
- padding-left: 1rem;
3181
- border-left-width: 3px;
3182
- border-left-color: var(--border);
3183
- color: var(--muted);
3184
- }
3185
- /* Code blocks */
3186
- .vprose pre {
3187
- margin-top: 0.75rem;
3188
- margin-bottom: 0.75rem;
3189
- padding: 0.75rem;
3190
- border-radius: 0.5rem;
3191
- overflow-x: auto;
3192
- background-color: var(--muted-background);
3193
- color: var(--foreground);
3194
- }
3195
- .vprose pre code {
3196
- color: inherit;
3197
- }
3198
- .dark .vprose pre {
3199
- color: var(--foreground);
3200
- }
3201
-
3202
- /* Summary chat markdown: keep structure, but match the app's quieter conversation surface. */
3203
- .agent-markdown {
3204
- color: color-mix(in oklch, var(--foreground) 78%, transparent);
3205
- font-size: 0.875rem;
3206
- line-height: 1.625;
3207
- overflow-x: auto;
3208
- }
3209
- .agent-markdown > * + * {
3210
- margin-top: 0.65rem;
3211
- }
3212
- .agent-markdown p {
3213
- margin-top: 0.5rem;
3214
- margin-bottom: 0.5rem;
3215
- }
3216
- .agent-markdown h1,
3217
- .agent-markdown h2,
3218
- .agent-markdown h3,
3219
- .agent-markdown h4 {
3220
- margin-top: 1.2rem;
3221
- margin-bottom: 0.45rem;
3222
- color: var(--foreground);
3223
- font-weight: 650;
3224
- letter-spacing: 0;
3225
- line-height: 1.3;
3226
- }
3227
- .agent-markdown h1 {
3228
- font-size: 1.2rem;
3229
- }
3230
- .agent-markdown h2 {
3231
- font-size: 1.05rem;
3232
- }
3233
- .agent-markdown h3,
3234
- .agent-markdown h4 {
3235
- font-size: 0.95rem;
3236
- }
3237
- .agent-markdown h1:first-child,
3238
- .agent-markdown h2:first-child,
3239
- .agent-markdown h3:first-child,
3240
- .agent-markdown h4:first-child {
3241
- margin-top: 0;
3242
- }
3243
- .agent-markdown hr {
3244
- margin: 1.15rem 0;
3245
- border: 0;
3246
- border-top: 1px solid var(--border);
3247
- opacity: 0.65;
3248
- }
3249
- .agent-markdown ul,
3250
- .agent-markdown ol {
3251
- margin-top: 0.55rem;
3252
- margin-bottom: 0.55rem;
3253
- padding-left: 1.25rem;
3254
- }
3255
- .agent-markdown li {
3256
- margin-top: 0.2rem;
3257
- margin-bottom: 0.2rem;
3258
- padding-left: 0.1rem;
3259
- color: inherit;
3260
- }
3261
- .agent-markdown li::marker {
3262
- color: var(--muted);
3263
- }
3264
- .agent-markdown strong {
3265
- color: var(--foreground);
3266
- font-weight: 600;
3267
- }
3268
- .agent-markdown em {
3269
- color: color-mix(in oklch, var(--foreground) 72%, transparent);
3270
- }
3271
- .agent-markdown a {
3272
- color: var(--foreground);
3273
- text-decoration-color: var(--muted);
3274
- text-underline-offset: 3px;
3275
- }
3276
- .agent-markdown blockquote {
3277
- margin-top: 0.85rem;
3278
- margin-bottom: 0.85rem;
3279
- padding-left: 0.875rem;
3280
- border-left: 2px solid var(--border);
3281
- color: var(--muted);
3282
- font-style: normal;
3283
- }
3284
- .agent-markdown :not(pre) > code {
3285
- border: 1px solid var(--border);
3286
- border-radius: 0.375rem;
3287
- background: var(--muted);
3288
- color: var(--foreground);
3289
- padding: 0.1rem 0.35rem;
3290
- font-size: 0.8125em;
3291
- font-weight: 500;
3292
- }
3293
- .agent-markdown pre {
3294
- margin-top: 0.85rem;
3295
- margin-bottom: 0.85rem;
3296
- max-height: 32rem;
3297
- overflow: auto;
3298
- border: 1px solid var(--border);
3299
- border-radius: 0.75rem;
3300
- background: var(--muted);
3301
- color: var(--foreground);
3302
- padding: 0.875rem;
3303
- font-size: 0.8125rem;
3304
- line-height: 1.55;
3305
- }
3306
- .agent-markdown pre code {
3307
- border: 0;
3308
- background: transparent;
3309
- color: inherit;
3310
- padding: 0;
3311
- font-size: inherit;
3312
- }
3313
- .agent-markdown table {
3314
- display: table;
3315
- width: 100%;
3316
- max-width: 100%;
3317
- margin: 0.9rem 0 1rem;
3318
- border: 0;
3319
- border-collapse: collapse;
3320
- border-spacing: 0;
3321
- font-size: 0.8125rem;
3322
- table-layout: fixed;
3323
- background: transparent;
3324
- }
3325
- .agent-markdown thead {
3326
- background: transparent;
3327
- }
3328
- .agent-markdown th,
3329
- .agent-markdown td {
3330
- border: 0;
3331
- border-bottom: 1px solid color-mix(in oklch, var(--border) 70%, transparent);
3332
- background: transparent;
3333
- padding: 0.55rem 0.75rem;
3334
- text-align: left;
3335
- vertical-align: top;
3336
- overflow-wrap: anywhere;
3337
- word-break: normal;
3338
- white-space: normal;
3339
- }
3340
- .agent-markdown th {
3341
- color: var(--muted);
3342
- font-size: 0.75rem;
3343
- font-weight: 600;
3344
- letter-spacing: 0;
3345
- text-transform: none;
3346
- white-space: nowrap;
3347
- }
3348
- .agent-markdown td {
3349
- color: inherit;
3350
- }
3351
- .agent-markdown th + th,
3352
- .agent-markdown td + td {
3353
- padding-inline-start: 1.75rem;
3354
- }
3355
- .agent-markdown th:first-child,
3356
- .agent-markdown td:first-child {
3357
- min-width: 0;
3358
- width: auto;
3359
- white-space: normal;
3360
- }
3361
- .agent-markdown col {
3362
- width: var(--agent-markdown-table-column-width);
3363
- }
3364
- .agent-markdown tr:last-child td {
3365
- border-bottom: 0;
3366
- }
3367
- .agent-markdown tbody tr:nth-child(even) {
3368
- background: transparent;
3369
- }
3370
- .agent-markdown tbody tr:hover {
3371
- background: transparent;
3372
- }
3373
- `}</style>
3122
+ <style>{agentMarkdownStyles}</style>
3374
3123
 
3375
3124
  {/* Workstream tabs are a debug affordance; Summary keeps the conversation surface quiet. */}
3376
3125
  {viewMode === 'stacked' && (
@@ -3,15 +3,9 @@ import { useUITranslation } from '@vertesia/ui/i18n';
3
3
  import { MarkdownRenderer, type MarkdownRendererProps } from '@vertesia/ui/widgets';
4
4
  import { ChevronDown } from 'lucide-react';
5
5
  import { useState } from 'react';
6
+ import { AGENT_PROSE_CLASS } from './agentMarkdownStyles.js';
6
7
 
7
- /** Prose styling used for agent/model message markdown, shared across the conversation UI. */
8
- export const AGENT_PROSE_CLASS = [
9
- 'agent-markdown vprose prose max-w-none break-words text-sm leading-6 text-foreground/80',
10
- 'prose-p:my-2 prose-p:leading-6 prose-li:my-0.5 prose-pre:my-3 prose-headings:tracking-normal',
11
- 'prose-headings:text-foreground prose-strong:text-foreground prose-code:text-foreground',
12
- 'prose-a:text-foreground prose-a:underline prose-a:decoration-muted prose-a:underline-offset-4',
13
- '[&_p]:text-foreground/80 [&_li]:text-foreground/80 [&_li::marker]:text-muted',
14
- ].join(' ');
8
+ export { AGENT_PROSE_CLASS } from './agentMarkdownStyles.js';
15
9
 
16
10
  /** Clamp applied to collapsed markdown. Kept as a literal so Tailwind emits the utility. */
17
11
  export const AGENT_LINE_CLAMP_CLASS =
@@ -0,0 +1,248 @@
1
+ /** Prose styling used for agent/model message markdown, shared across the conversation UI. */
2
+ export const AGENT_PROSE_CLASS = [
3
+ 'agent-markdown vprose prose max-w-none break-words text-sm leading-6 text-foreground/80',
4
+ 'prose-p:my-2 prose-p:leading-6 prose-li:my-0.5 prose-pre:my-3 prose-headings:tracking-normal',
5
+ 'prose-headings:text-foreground prose-strong:text-foreground prose-code:text-foreground',
6
+ 'prose-a:text-foreground prose-a:underline prose-a:decoration-muted prose-a:underline-offset-4',
7
+ 'prose-p:text-foreground/80 prose-li:text-foreground/80 prose-li:marker:text-muted',
8
+ ].join(' ');
9
+
10
+ // Shared with rendered regression checks so they exercise the styles the chat actually injects.
11
+ export const agentMarkdownStyles = `
12
+ /* Better vertical rhythm for markdown */
13
+ .vprose > * + *:not(:where(.not-prose, .not-prose *)) {
14
+ margin-top: 0.625rem;
15
+ }
16
+ .vprose > h1 + *:not(:where(.not-prose, .not-prose *)),
17
+ .vprose > h2 + *:not(:where(.not-prose, .not-prose *)),
18
+ .vprose > h3 + *:not(:where(.not-prose, .not-prose *)) {
19
+ margin-top: 0.375rem;
20
+ }
21
+ /* Tables should read like part of the conversation, not a separate app grid. */
22
+ .vprose table:not(:where(.not-prose, .not-prose *)) {
23
+ margin-top: 0.875rem;
24
+ margin-bottom: 0.875rem;
25
+ border-collapse: collapse;
26
+ width: 100%;
27
+ background: transparent;
28
+ }
29
+ .vprose th:not(:where(.not-prose, .not-prose *)),
30
+ .vprose td:not(:where(.not-prose, .not-prose *)) {
31
+ padding: 0.5rem 0.625rem;
32
+ border: 0;
33
+ border-bottom: 1px solid color-mix(in oklch, var(--border) 70%, transparent);
34
+ background: transparent;
35
+ text-align: left;
36
+ }
37
+ .vprose thead th:not(:where(.not-prose, .not-prose *)) {
38
+ background: transparent;
39
+ font-weight: 600;
40
+ color: var(--muted);
41
+ font-size: 0.75rem;
42
+ text-transform: none;
43
+ letter-spacing: 0;
44
+ }
45
+ .vprose tbody tr:hover:not(:where(.not-prose, .not-prose *)) {
46
+ background: transparent;
47
+ }
48
+ /* Horizontal rules as section dividers */
49
+ .vprose hr:not(:where(.not-prose, .not-prose *)) {
50
+ margin-top: 1rem;
51
+ margin-bottom: 1rem;
52
+ border-color: var(--border);
53
+ }
54
+ /* Better blockquote styling */
55
+ .vprose blockquote:not(:where(.not-prose, .not-prose *)) {
56
+ margin-top: 0.875rem;
57
+ margin-bottom: 0.875rem;
58
+ padding-left: 1rem;
59
+ border-left-width: 3px;
60
+ border-left-color: var(--border);
61
+ color: var(--muted);
62
+ }
63
+ /* Code blocks */
64
+ .vprose pre:not(:where(.not-prose, .not-prose *)) {
65
+ margin-top: 0.75rem;
66
+ margin-bottom: 0.75rem;
67
+ padding: 0.75rem;
68
+ border-radius: 0.5rem;
69
+ overflow-x: auto;
70
+ background-color: var(--muted-background);
71
+ color: var(--foreground);
72
+ }
73
+ .vprose pre code:not(:where(.not-prose, .not-prose *)) {
74
+ color: inherit;
75
+ }
76
+
77
+ /* Summary chat markdown: keep structure, but match the app's quieter conversation surface. */
78
+ .agent-markdown:not(:where(.not-prose, .not-prose *)) {
79
+ color: color-mix(in oklch, var(--foreground) 78%, transparent);
80
+ font-size: 0.875rem;
81
+ line-height: 1.625;
82
+ overflow-x: auto;
83
+ }
84
+ .agent-markdown > * + *:not(:where(.not-prose, .not-prose *)) {
85
+ margin-top: 0.65rem;
86
+ }
87
+ .agent-markdown p:not(:where(.not-prose, .not-prose *)) {
88
+ margin-top: 0.5rem;
89
+ margin-bottom: 0.5rem;
90
+ }
91
+ .agent-markdown h1:not(:where(.not-prose, .not-prose *)),
92
+ .agent-markdown h2:not(:where(.not-prose, .not-prose *)),
93
+ .agent-markdown h3:not(:where(.not-prose, .not-prose *)),
94
+ .agent-markdown h4:not(:where(.not-prose, .not-prose *)) {
95
+ margin-top: 1.2rem;
96
+ margin-bottom: 0.45rem;
97
+ color: var(--foreground);
98
+ font-weight: 650;
99
+ letter-spacing: 0;
100
+ line-height: 1.3;
101
+ }
102
+ .agent-markdown h1:not(:where(.not-prose, .not-prose *)) {
103
+ font-size: 1.2rem;
104
+ }
105
+ .agent-markdown h2:not(:where(.not-prose, .not-prose *)) {
106
+ font-size: 1.05rem;
107
+ }
108
+ .agent-markdown h3:not(:where(.not-prose, .not-prose *)),
109
+ .agent-markdown h4:not(:where(.not-prose, .not-prose *)) {
110
+ font-size: 0.95rem;
111
+ }
112
+ .agent-markdown h1:first-child:not(:where(.not-prose, .not-prose *)),
113
+ .agent-markdown h2:first-child:not(:where(.not-prose, .not-prose *)),
114
+ .agent-markdown h3:first-child:not(:where(.not-prose, .not-prose *)),
115
+ .agent-markdown h4:first-child:not(:where(.not-prose, .not-prose *)) {
116
+ margin-top: 0;
117
+ }
118
+ .agent-markdown hr:not(:where(.not-prose, .not-prose *)) {
119
+ margin: 1.15rem 0;
120
+ border: 0;
121
+ border-top: 1px solid var(--border);
122
+ opacity: 0.65;
123
+ }
124
+ .agent-markdown ul:not(:where(.not-prose, .not-prose *)),
125
+ .agent-markdown ol:not(:where(.not-prose, .not-prose *)) {
126
+ margin-top: 0.55rem;
127
+ margin-bottom: 0.55rem;
128
+ padding-left: 1.25rem;
129
+ }
130
+ .agent-markdown li:not(:where(.not-prose, .not-prose *)) {
131
+ margin-top: 0.2rem;
132
+ margin-bottom: 0.2rem;
133
+ padding-left: 0.1rem;
134
+ color: inherit;
135
+ }
136
+ .agent-markdown li:not(:where(.not-prose, .not-prose *))::marker {
137
+ color: var(--muted);
138
+ }
139
+ .agent-markdown strong:not(:where(.not-prose, .not-prose *)) {
140
+ color: var(--foreground);
141
+ font-weight: 600;
142
+ }
143
+ .agent-markdown em:not(:where(.not-prose, .not-prose *)) {
144
+ color: color-mix(in oklch, var(--foreground) 72%, transparent);
145
+ }
146
+ .agent-markdown a:not(:where(.not-prose, .not-prose *)) {
147
+ color: var(--foreground);
148
+ text-decoration-color: var(--muted);
149
+ text-underline-offset: 3px;
150
+ }
151
+ .agent-markdown blockquote:not(:where(.not-prose, .not-prose *)) {
152
+ margin-top: 0.85rem;
153
+ margin-bottom: 0.85rem;
154
+ padding-left: 0.875rem;
155
+ border-left: 2px solid var(--border);
156
+ color: var(--muted);
157
+ font-style: normal;
158
+ }
159
+ .agent-markdown :not(pre) > code:not(:where(.not-prose, .not-prose *)) {
160
+ border: 1px solid var(--border);
161
+ border-radius: 0.375rem;
162
+ background: var(--muted-background);
163
+ color: var(--foreground);
164
+ padding: 0.1rem 0.35rem;
165
+ font-size: 0.8125em;
166
+ font-weight: 500;
167
+ }
168
+ .agent-markdown pre:not(:where(.not-prose, .not-prose *)) {
169
+ margin-top: 0.85rem;
170
+ margin-bottom: 0.85rem;
171
+ max-height: 32rem;
172
+ overflow: auto;
173
+ border: 1px solid var(--border);
174
+ border-radius: 0.75rem;
175
+ background: var(--muted-background);
176
+ color: var(--foreground);
177
+ padding: 0.875rem;
178
+ font-size: 0.8125rem;
179
+ line-height: 1.55;
180
+ }
181
+ .agent-markdown pre code:not(:where(.not-prose, .not-prose *)) {
182
+ border: 0;
183
+ background: transparent;
184
+ color: inherit;
185
+ padding: 0;
186
+ font-size: inherit;
187
+ }
188
+ .agent-markdown table:not(:where(.not-prose, .not-prose *)) {
189
+ display: table;
190
+ width: 100%;
191
+ max-width: 100%;
192
+ margin: 0.9rem 0 1rem;
193
+ border: 0;
194
+ border-collapse: collapse;
195
+ border-spacing: 0;
196
+ font-size: 0.8125rem;
197
+ table-layout: fixed;
198
+ background: transparent;
199
+ }
200
+ .agent-markdown thead:not(:where(.not-prose, .not-prose *)) {
201
+ background: transparent;
202
+ }
203
+ .agent-markdown th:not(:where(.not-prose, .not-prose *)),
204
+ .agent-markdown td:not(:where(.not-prose, .not-prose *)) {
205
+ border: 0;
206
+ border-bottom: 1px solid color-mix(in oklch, var(--border) 70%, transparent);
207
+ background: transparent;
208
+ padding: 0.55rem 0.75rem;
209
+ text-align: left;
210
+ vertical-align: top;
211
+ overflow-wrap: anywhere;
212
+ word-break: normal;
213
+ white-space: normal;
214
+ }
215
+ .agent-markdown th:not(:where(.not-prose, .not-prose *)) {
216
+ color: var(--muted);
217
+ font-size: 0.75rem;
218
+ font-weight: 600;
219
+ letter-spacing: 0;
220
+ text-transform: none;
221
+ white-space: nowrap;
222
+ }
223
+ .agent-markdown td:not(:where(.not-prose, .not-prose *)) {
224
+ color: inherit;
225
+ }
226
+ .agent-markdown th + th:not(:where(.not-prose, .not-prose *)),
227
+ .agent-markdown td + td:not(:where(.not-prose, .not-prose *)) {
228
+ padding-inline-start: 1.75rem;
229
+ }
230
+ .agent-markdown th:first-child:not(:where(.not-prose, .not-prose *)),
231
+ .agent-markdown td:first-child:not(:where(.not-prose, .not-prose *)) {
232
+ min-width: 0;
233
+ width: auto;
234
+ white-space: normal;
235
+ }
236
+ .agent-markdown col:not(:where(.not-prose, .not-prose *)) {
237
+ width: var(--agent-markdown-table-column-width);
238
+ }
239
+ .agent-markdown tr:last-child td:not(:where(.not-prose, .not-prose *)) {
240
+ border-bottom: 0;
241
+ }
242
+ .agent-markdown tbody tr:nth-child(even):not(:where(.not-prose, .not-prose *)) {
243
+ background: transparent;
244
+ }
245
+ .agent-markdown tbody tr:hover:not(:where(.not-prose, .not-prose *)) {
246
+ background: transparent;
247
+ }
248
+ `;
@@ -1,5 +1,6 @@
1
1
  import { ContentNature, type ContentObject, ImageRenditionFormat } from '@vertesia/common';
2
- import { Spinner } from '@vertesia/ui/core';
2
+ import { Button, Spinner } from '@vertesia/ui/core';
3
+ import { useUITranslation } from '@vertesia/ui/i18n';
3
4
  import { useUserSession } from '@vertesia/ui/session';
4
5
  import { useEffect, useState } from 'react';
5
6
  import { WEB_SUPPORTED_IMAGE_FORMATS } from './formats.js';
@@ -19,12 +20,27 @@ interface ImagePanelProps {
19
20
  * Renders an image from a direct URL, a storage source path, or a Vertesia ContentObject.
20
21
  * Resolution priority: `url` > `source` > `object`.
21
22
  */
22
- export function ImagePanel({ url, source, object, className }: ImagePanelProps) {
23
+ export function ImagePanel(props: ImagePanelProps) {
24
+ const [attempt, setAttempt] = useState(0);
25
+ const identity =
26
+ props.url ??
27
+ props.source ??
28
+ `${props.object?.id}:${props.object?.content?.source}:${props.object?.content?.etag}`;
29
+ return (
30
+ <ImagePanelContent key={`${identity}:${attempt}`} {...props} onRetry={() => setAttempt((value) => value + 1)} />
31
+ );
32
+ }
33
+
34
+ function ImagePanelContent({ url, source, object, className, onRetry }: ImagePanelProps & { onRetry: () => void }) {
35
+ const { t } = useUITranslation();
36
+ const [failed, setFailed] = useState(false);
23
37
  const { client } = useUserSession();
24
38
  const [imageUrl, setImageUrl] = useState<string | undefined>(url);
25
39
  const [isLoading, setIsLoading] = useState<boolean>(!url && (!!source || !!object));
26
40
 
27
41
  useEffect(() => {
42
+ let active = true;
43
+ setFailed(false);
28
44
  if (url) {
29
45
  setImageUrl(url);
30
46
  setIsLoading(false);
@@ -37,17 +53,17 @@ export function ImagePanel({ url, source, object, className }: ImagePanelProps)
37
53
  try {
38
54
  if (source) {
39
55
  const downloadUrl = await client.files.getDownloadUrl(source);
40
- setImageUrl(downloadUrl.url);
56
+ if (active) setImageUrl(downloadUrl.url);
41
57
  return;
42
58
  }
43
59
 
44
60
  if (!object) return;
45
61
 
46
- const isImage = object.metadata?.type === ContentNature.Image;
62
+ const mime = object.content?.type?.split(';', 1)[0].trim().toLowerCase();
63
+ const isImage = object.metadata?.type === ContentNature.Image || mime?.startsWith('image/');
47
64
  if (!isImage) return;
48
65
 
49
- const isOriginalWebSupported =
50
- object.content?.type && WEB_SUPPORTED_IMAGE_FORMATS.includes(object.content.type);
66
+ const isOriginalWebSupported = mime && WEB_SUPPORTED_IMAGE_FORMATS.includes(mime);
51
67
 
52
68
  try {
53
69
  const rendition = await client.objects.getRendition(object.id, {
@@ -56,7 +72,7 @@ export function ImagePanel({ url, source, object, className }: ImagePanelProps)
56
72
  sign_url: true,
57
73
  });
58
74
  if (rendition.status === 'found' && rendition.renditions?.length) {
59
- setImageUrl(rendition.renditions[0]);
75
+ if (active) setImageUrl(rendition.renditions[0]);
60
76
  return;
61
77
  }
62
78
  } catch {
@@ -65,10 +81,14 @@ export function ImagePanel({ url, source, object, className }: ImagePanelProps)
65
81
 
66
82
  if (isOriginalWebSupported && object.content?.source) {
67
83
  const downloadUrl = await client.files.getDownloadUrl(object.content.source);
68
- setImageUrl(downloadUrl.url);
84
+ if (active) setImageUrl(downloadUrl.url);
85
+ } else if (active) {
86
+ setFailed(true);
69
87
  }
88
+ } catch {
89
+ if (active) setFailed(true);
70
90
  } finally {
71
- setIsLoading(false);
91
+ if (active) setIsLoading(false);
72
92
  }
73
93
  };
74
94
 
@@ -78,6 +98,9 @@ export function ImagePanel({ url, source, object, className }: ImagePanelProps)
78
98
  } else {
79
99
  setIsLoading(false);
80
100
  }
101
+ return () => {
102
+ active = false;
103
+ };
81
104
  }, [url, source, object, client]);
82
105
 
83
106
  if (isLoading) {
@@ -88,9 +111,27 @@ export function ImagePanel({ url, source, object, className }: ImagePanelProps)
88
111
  );
89
112
  }
90
113
 
114
+ if (failed) {
115
+ return (
116
+ <div role="alert" className={`flex flex-col items-center gap-2 p-4 ${className ?? ''}`.trim()}>
117
+ <p>{t('store.failedToLoadDocument')}</p>
118
+ <Button variant="outline" onClick={onRetry}>
119
+ {t('agent.retry')}
120
+ </Button>
121
+ </div>
122
+ );
123
+ }
124
+
91
125
  if (!imageUrl) {
92
126
  return null;
93
127
  }
94
128
 
95
- return <img src={imageUrl} alt={object?.name} className={`w-full object-contain ${className ?? ''}`.trim()} />;
129
+ return (
130
+ <img
131
+ src={imageUrl}
132
+ alt={object?.name ?? t('intakePolicy.option.image')}
133
+ onError={() => setFailed(true)}
134
+ className={`w-full object-contain ${className ?? ''}`.trim()}
135
+ />
136
+ );
96
137
  }
@@ -547,6 +547,7 @@ export function IntakePolicyEditor({
547
547
  <div className="flex h-full min-h-0 w-full flex-col gap-2">
548
548
  <IntakeSummary policy={summaryPolicy} />
549
549
  <Tabs
550
+ orientation="vertical"
550
551
  tabs={leadingTabs ? [...leadingTabs, ...policyTabs] : policyTabs}
551
552
  current={activeTab}
552
553
  onTabChange={onTabChange}
@@ -554,7 +555,7 @@ export function IntakePolicyEditor({
554
555
  fullHeight
555
556
  className="px-0 min-h-0 flex-1 flex-row!"
556
557
  >
557
- <TabsBar className="py-2 w-48 shrink-0" direction="vertical" />
558
+ <TabsBar className="py-2 w-48 shrink-0" />
558
559
  <TabsPanel className="min-h-0 min-w-0 flex-1 overflow-auto pb-0!" />
559
560
  </Tabs>
560
561
  </div>