zidane-ui 9.1.13 → 9.1.16

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 (290) hide show
  1. package/dist/adapters/index.d.ts +2 -2
  2. package/dist/adapters/index.js +2 -2
  3. package/dist/adapters/live.d.ts +29 -3
  4. package/dist/adapters/live.js +9 -1
  5. package/dist/adapters/server-composer-host.js +17 -2
  6. package/dist/adapters/server-extensions-host.d.ts +0 -1
  7. package/dist/adapters/server-extensions-host.js +4 -15
  8. package/dist/adapters/server-git-host.js +7 -16
  9. package/dist/adapters/server-host.js +181 -43
  10. package/dist/adapters/server-machines-host.d.ts +2 -0
  11. package/dist/adapters/server-machines-host.js +22 -23
  12. package/dist/adapters/server-onboarding-host.d.ts +1 -1
  13. package/dist/adapters/server-onboarding-host.js +3 -4
  14. package/dist/adapters/server-session-host.js +22 -3
  15. package/dist/adapters/server-settings-accounts.js +2 -2
  16. package/dist/adapters/server-settings-host.js +2 -2
  17. package/dist/adapters/server-settings-performance.js +7 -9
  18. package/dist/adapters/server-settings-sections.js +13 -14
  19. package/dist/adapters/server-sidebar-host.js +2 -2
  20. package/dist/adapters/sse-host.js +68 -3
  21. package/dist/adapters/sse-protocol.d.ts +12 -2
  22. package/dist/adapters/sse-protocol.js +4 -2
  23. package/dist/app/AppHostProvider.js +4 -3
  24. package/dist/app/ModalProvider.d.ts +13 -3
  25. package/dist/app/ModalProvider.js +103 -24
  26. package/dist/app/NoticeStack.d.ts +33 -0
  27. package/dist/app/NoticeStack.js +90 -0
  28. package/dist/app/index.d.ts +3 -2
  29. package/dist/app/index.js +3 -2
  30. package/dist/chat/SessionFilterMenu.d.ts +1 -1
  31. package/dist/chat/SessionFilterMenu.js +2 -1
  32. package/dist/chat/composer/Composer.js +10 -8
  33. package/dist/chat/composer/ModelChainList.js +17 -8
  34. package/dist/chat/composer/ModelChainTooltip.js +5 -2
  35. package/dist/chat/composer/use-draft-target.d.ts +20 -1
  36. package/dist/chat/composer/use-draft-target.js +121 -5
  37. package/dist/chat/composer/use-new-session-defaults.d.ts +5 -1
  38. package/dist/chat/composer/use-new-session-defaults.js +17 -4
  39. package/dist/chat/headless/chip-labels.d.ts +1 -0
  40. package/dist/chat/headless/chip-labels.js +1 -0
  41. package/dist/chat/headless/composer/labels-editor.d.ts +0 -2
  42. package/dist/chat/headless/composer/labels-editor.js +0 -2
  43. package/dist/chat/headless/draft-target.d.ts +21 -1
  44. package/dist/chat/headless/fixture-host.js +17 -2
  45. package/dist/chat/headless/host.d.ts +3 -3
  46. package/dist/chat/headless/index.d.ts +9 -9
  47. package/dist/chat/headless/index.js +2 -2
  48. package/dist/chat/headless/labels.d.ts +13 -6
  49. package/dist/chat/headless/labels.js +10 -9
  50. package/dist/chat/headless/session-list.d.ts +20 -8
  51. package/dist/chat/headless/session-list.js +1 -0
  52. package/dist/chat/headless/sidebar/directory.d.ts +56 -14
  53. package/dist/chat/headless/sidebar/directory.js +149 -70
  54. package/dist/chat/headless/sidebar/index.d.ts +3 -3
  55. package/dist/chat/headless/sidebar/index.js +2 -2
  56. package/dist/chat/headless/sidebar/labels.d.ts +15 -8
  57. package/dist/chat/headless/sidebar/types.d.ts +3 -1
  58. package/dist/chat/headless/sidebar/view.d.ts +13 -5
  59. package/dist/chat/headless/sidebar/view.js +31 -11
  60. package/dist/chat/headless/streams/actions.d.ts +5 -3
  61. package/dist/chat/headless/streams/actions.js +3 -2
  62. package/dist/chat/headless/streams/index.d.ts +3 -3
  63. package/dist/chat/headless/streams/merge.d.ts +6 -10
  64. package/dist/chat/headless/streams/merge.js +7 -21
  65. package/dist/chat/headless/streams/session-streams.d.ts +29 -4
  66. package/dist/chat/headless/streams/session-streams.js +86 -0
  67. package/dist/chat/headless/streams/store.d.ts +162 -16
  68. package/dist/chat/headless/streams/store.js +334 -38
  69. package/dist/chat/headless/streams/types.d.ts +10 -7
  70. package/dist/chat/headless/transcript-labels.d.ts +1 -0
  71. package/dist/chat/interactions/PlanCard.js +10 -3
  72. package/dist/chat/interactions/QuestionForm.js +7 -3
  73. package/dist/chat/interactions/card-ui.d.ts +5 -3
  74. package/dist/chat/interactions/card-ui.js +9 -7
  75. package/dist/chat/rich-composer/RichComposer.js +1 -7
  76. package/dist/chat/rich-composer/composer-extensions.d.ts +0 -2
  77. package/dist/chat/rich-composer/composer-extensions.js +2 -2
  78. package/dist/chat/rich-composer/use-composer-editor.d.ts +0 -2
  79. package/dist/chat/rich-composer/use-composer-editor.js +1 -2
  80. package/dist/chat/sidebar/SessionSidebar.js +5 -5
  81. package/dist/chat/sidebar/SidebarFilterMenu.js +3 -1
  82. package/dist/chat/sidebar/SidebarFrame.d.ts +4 -0
  83. package/dist/chat/sidebar/SidebarFrame.js +27 -9
  84. package/dist/chat/sidebar/SidebarGroupHeader.js +1 -1
  85. package/dist/chat/sidebar/SidebarHostProvider.d.ts +8 -5
  86. package/dist/chat/sidebar/SidebarHostProvider.js +13 -9
  87. package/dist/chat/sidebar/SidebarToggleButton.js +7 -3
  88. package/dist/chat/sidebar/index.d.ts +2 -2
  89. package/dist/chat/sidebar/session-menu.js +4 -4
  90. package/dist/chat/sidebar/useSaveViewAsSpace.js +2 -2
  91. package/dist/chat/testing/contract.js +2 -2
  92. package/dist/chat/transcript/AuthFailureCard.js +11 -8
  93. package/dist/chat/transcript/BadgeMenu.js +13 -2
  94. package/dist/chat/transcript/MermaidDiagram.js +7 -3
  95. package/dist/chat/transcript/fold.d.ts +4 -0
  96. package/dist/chat/transcript/fold.js +53 -22
  97. package/dist/chat/transcript/script-input.d.ts +1 -1
  98. package/dist/chat/transcript/shell-block.js +7 -3
  99. package/dist/chat/transcript/useStickToBottom.js +12 -0
  100. package/dist/components/BrowserSignIn.js +23 -21
  101. package/dist/components/Form.d.ts +6 -4
  102. package/dist/components/Form.js +16 -8
  103. package/dist/components/LoadError.d.ts +4 -2
  104. package/dist/components/LoadError.js +13 -9
  105. package/dist/components/Notice.d.ts +29 -0
  106. package/dist/components/Notice.js +63 -0
  107. package/dist/components/PanelEmpty.d.ts +1 -1
  108. package/dist/components/PanelEmpty.js +4 -2
  109. package/dist/components/Restricted.d.ts +1 -1
  110. package/dist/components/palette/PaletteList.js +8 -1
  111. package/dist/components/palette/PalettePanel.js +14 -6
  112. package/dist/core.css +24 -5
  113. package/dist/dist/{index-Bq87OcGy.d.ts → index-BZM8tu4L.d.ts} +28 -3
  114. package/dist/dist/index.d.ts +2 -2
  115. package/dist/dist/{timeout-B5pO5I5a.d.ts → timeout-Cyx3VGPz.d.ts} +1 -1
  116. package/dist/extensions/ExtensionSettingsPage.js +1 -4
  117. package/dist/extensions/ExtensionSettingsSection.js +4 -3
  118. package/dist/extensions/ExtensionSettingsSidebar.js +2 -6
  119. package/dist/extensions/SettingsWireForm.d.ts +1 -7
  120. package/dist/extensions/SettingsWireForm.js +7 -5
  121. package/dist/extensions/headless/fixture-host.d.ts +1 -5
  122. package/dist/extensions/headless/fixture-host.js +1 -4
  123. package/dist/extensions/headless/host.d.ts +1 -11
  124. package/dist/extensions/headless/index.d.ts +3 -3
  125. package/dist/extensions/headless/index.js +2 -2
  126. package/dist/extensions/headless/select.d.ts +1 -11
  127. package/dist/extensions/headless/select.js +1 -18
  128. package/dist/files/EditorColumn.js +12 -1
  129. package/dist/files/TreeColumn.js +13 -20
  130. package/dist/files/useOpenFiles.js +2 -0
  131. package/dist/git/BranchMenu.js +5 -3
  132. package/dist/git/ImportRepoDialog.js +18 -9
  133. package/dist/git/MoveSessionDialog.js +15 -7
  134. package/dist/git/RemoteFolderPicker.js +34 -16
  135. package/dist/git/SyncChip.js +17 -17
  136. package/dist/git/WherePicker.d.ts +16 -1
  137. package/dist/git/WherePicker.js +80 -36
  138. package/dist/git/headless/environment.d.ts +33 -3
  139. package/dist/git/headless/environment.js +33 -5
  140. package/dist/git/headless/index.d.ts +2 -2
  141. package/dist/git/headless/index.js +2 -2
  142. package/dist/git/headless/labels.d.ts +15 -2
  143. package/dist/git/headless/labels.js +17 -4
  144. package/dist/git/useEnvironmentChoices.d.ts +3 -1
  145. package/dist/git/useEnvironmentChoices.js +6 -3
  146. package/dist/index.d.ts +2 -1
  147. package/dist/index.js +2 -1
  148. package/dist/labels.d.ts +5 -0
  149. package/dist/labels.js +5 -0
  150. package/dist/machines/AddMachineDialog.d.ts +34 -0
  151. package/dist/machines/AddMachineDialog.js +464 -0
  152. package/dist/machines/Banners.d.ts +33 -4
  153. package/dist/machines/Banners.js +64 -3
  154. package/dist/machines/DaemonMenu.js +27 -4
  155. package/dist/machines/HostCapabilities.d.ts +1 -3
  156. package/dist/machines/HostCapabilities.js +24 -45
  157. package/dist/machines/HostSyncPanel.js +123 -129
  158. package/dist/machines/HostsSection.d.ts +4 -1
  159. package/dist/machines/HostsSection.js +30 -7
  160. package/dist/machines/MachinesExplainer.d.ts +17 -0
  161. package/dist/machines/MachinesExplainer.js +71 -0
  162. package/dist/machines/MachinesProvider.d.ts +14 -2
  163. package/dist/machines/MachinesProvider.js +35 -1
  164. package/dist/machines/ServerAddedCard.d.ts +31 -0
  165. package/dist/machines/ServerAddedCard.js +72 -0
  166. package/dist/machines/ServerCard.js +91 -215
  167. package/dist/machines/ServerMachinesPanel.d.ts +2 -2
  168. package/dist/machines/ServerMachinesPanel.js +184 -323
  169. package/dist/machines/ServerUpdatePanel.js +51 -40
  170. package/dist/machines/ShareThisComputerForm.d.ts +19 -0
  171. package/dist/machines/ShareThisComputerForm.js +133 -0
  172. package/dist/machines/TokensPanel.d.ts +5 -3
  173. package/dist/machines/TokensPanel.js +98 -78
  174. package/dist/machines/headless/fixture-host.d.ts +19 -3
  175. package/dist/machines/headless/fixture-host.js +42 -5
  176. package/dist/machines/headless/fixtures.js +4 -6
  177. package/dist/machines/headless/host.d.ts +40 -19
  178. package/dist/machines/headless/index.d.ts +3 -3
  179. package/dist/machines/headless/index.js +2 -2
  180. package/dist/machines/headless/labels.d.ts +63 -20
  181. package/dist/machines/headless/labels.js +88 -25
  182. package/dist/machines/headless/messages.js +8 -0
  183. package/dist/machines/headless/stores.d.ts +9 -2
  184. package/dist/machines/headless/stores.js +28 -1
  185. package/dist/machines/index.d.ts +7 -3
  186. package/dist/machines/index.js +8 -4
  187. package/dist/machines/testing/contract.d.ts +15 -3
  188. package/dist/machines/testing/contract.js +68 -14
  189. package/dist/motion/grow.d.ts +8 -1
  190. package/dist/motion/grow.js +10 -4
  191. package/dist/onboarding/demos/index.js +1 -1
  192. package/dist/onboarding/headless/labels.d.ts +13 -0
  193. package/dist/onboarding/headless/labels.js +8 -0
  194. package/dist/onboarding/index.js +3 -3
  195. package/dist/onboarding/sources/SourceBrowser.js +11 -7
  196. package/dist/onboarding/steps/ConnectorsStep.js +1 -1
  197. package/dist/onboarding/steps/ImportStep.js +4 -1
  198. package/dist/onboarding/steps/ReadyStep.js +9 -2
  199. package/dist/onboarding/steps/SkillsStep.js +1 -1
  200. package/dist/onboarding/steps/connect/KeyForm.js +6 -2
  201. package/dist/onboarding/steps/connect/ProviderPanel.js +6 -2
  202. package/dist/onboarding/steps/connect/ProviderReady.js +25 -20
  203. package/dist/onboarding/steps/tasks.js +17 -14
  204. package/dist/server/sse-handler.js +141 -19
  205. package/dist/session/ArtifactsPanel.js +39 -17
  206. package/dist/session/PlanTracker.js +12 -7
  207. package/dist/session/ProjectHome.js +13 -11
  208. package/dist/session/RemindersPanel.js +34 -16
  209. package/dist/session/RunningWorkDialog.js +6 -2
  210. package/dist/session/SecretsPanel.js +29 -10
  211. package/dist/session/SessionDetailsDialog.d.ts +1 -1
  212. package/dist/session/SessionDetailsDialog.js +18 -10
  213. package/dist/session/SideChat.js +10 -7
  214. package/dist/session/TurnDetailsDialog.js +19 -5
  215. package/dist/session/UsagePanel.js +10 -4
  216. package/dist/session/headless/host.d.ts +2 -0
  217. package/dist/session/headless/labels.d.ts +19 -1
  218. package/dist/session/headless/labels.js +15 -1
  219. package/dist/session/headless/queue.js +2 -1
  220. package/dist/session/headless/reminder-labels.d.ts +4 -0
  221. package/dist/session/headless/reminder-labels.js +4 -0
  222. package/dist/settings/SettingsRestricted.d.ts +1 -1
  223. package/dist/settings/SettingsRestricted.js +4 -4
  224. package/dist/settings/SettingsShell.d.ts +7 -0
  225. package/dist/settings/SettingsShell.js +6 -1
  226. package/dist/settings/headless/fixture-performance.d.ts +1 -1
  227. package/dist/settings/headless/host.d.ts +2 -2
  228. package/dist/settings/headless/labels.d.ts +3 -3
  229. package/dist/settings/headless/labels.js +3 -3
  230. package/dist/settings/headless/performance.d.ts +3 -4
  231. package/dist/settings/headless/search.d.ts +1 -1
  232. package/dist/settings/index.d.ts +2 -1
  233. package/dist/settings/index.js +2 -1
  234. package/dist/settings/sections/editor/EditorSection.js +7 -4
  235. package/dist/settings/sections/editor/labels.d.ts +1 -0
  236. package/dist/settings/sections/editor/labels.js +1 -0
  237. package/dist/settings/sections/environments/EnvironmentsSection.js +19 -12
  238. package/dist/settings/sections/environments/labels.d.ts +1 -0
  239. package/dist/settings/sections/environments/labels.js +2 -1
  240. package/dist/settings/sections/extensions/ExtensionConfigRows.d.ts +1 -3
  241. package/dist/settings/sections/extensions/ExtensionConfigRows.js +20 -19
  242. package/dist/settings/sections/extensions/ExtensionOptionsSection.js +2 -1
  243. package/dist/settings/sections/extensions/options-labels.d.ts +2 -1
  244. package/dist/settings/sections/extensions/options-labels.js +2 -1
  245. package/dist/settings/sections/index.d.ts +2 -1
  246. package/dist/settings/sections/index.js +2 -1
  247. package/dist/settings/sections/logs/LogsSection.d.ts +2 -2
  248. package/dist/settings/sections/logs/LogsSection.js +2 -2
  249. package/dist/settings/sections/mcp/McpSection.d.ts +1 -1
  250. package/dist/settings/sections/mcp/McpSection.js +12 -6
  251. package/dist/settings/sections/mcp/McpServerRow.js +20 -13
  252. package/dist/settings/sections/mcp/labels.d.ts +8 -2
  253. package/dist/settings/sections/mcp/labels.js +8 -2
  254. package/dist/settings/sections/models/ModelRows.js +1 -1
  255. package/dist/settings/sections/models/NewChatPlaceRow.d.ts +26 -0
  256. package/dist/settings/sections/models/NewChatPlaceRow.js +78 -0
  257. package/dist/settings/sections/models/SpacesDefaultsSection.js +15 -3
  258. package/dist/settings/sections/models/labels.d.ts +7 -0
  259. package/dist/settings/sections/models/labels.js +7 -0
  260. package/dist/settings/sections/models/model-test.js +7 -4
  261. package/dist/settings/sections/performance/PerformanceSection.js +16 -6
  262. package/dist/settings/sections/performance/labels.d.ts +1 -1
  263. package/dist/settings/sections/performance/labels.js +1 -1
  264. package/dist/settings/sections/providers/ProvidersSection.d.ts +1 -1
  265. package/dist/settings/sections/providers/ProvidersSection.js +14 -7
  266. package/dist/settings/sections/providers/ServerProvidersSection.d.ts +1 -1
  267. package/dist/settings/sections/providers/ServerProvidersSection.js +11 -5
  268. package/dist/settings/sections/providers/labels.d.ts +2 -2
  269. package/dist/settings/sections/providers/labels.js +2 -2
  270. package/dist/settings/sections/skills/SkillList.js +1 -1
  271. package/dist/settings/sections/skills/SkillsSection.js +1 -1
  272. package/dist/settings/testing/performance.contract.js +8 -12
  273. package/dist/styles.css +32 -3
  274. package/dist/terminal/HostTerminalSurface.js +15 -5
  275. package/dist/terminal/TerminalPanel.js +30 -17
  276. package/dist/terminal/TerminalSurface.js +11 -4
  277. package/dist/terminal/headless/labels.d.ts +5 -0
  278. package/dist/terminal/headless/labels.js +5 -0
  279. package/dist/terminal/headless/store.d.ts +1 -1
  280. package/dist/terminal/headless/store.js +6 -3
  281. package/dist/workspace/LayoutBudget.d.ts +5 -1
  282. package/dist/workspace/LayoutBudget.js +14 -1
  283. package/dist/workspace/PanelContentView.d.ts +1 -1
  284. package/dist/workspace/PanelContentView.js +17 -6
  285. package/dist/workspace/WorkspaceProvider.js +3 -2
  286. package/dist/workspace/headless/labels.d.ts +1 -0
  287. package/dist/workspace/headless/labels.js +1 -0
  288. package/package.json +3 -3
  289. package/src/styles/motion.css +8 -0
  290. package/src/styles/primitives.css +7 -0
@@ -5,7 +5,7 @@ import { buttonClass } from "../components/button.js";
5
5
  import { ErrorBoundary, ErrorDetails } from "../components/ErrorBoundary.js";
6
6
  import { Keycap } from "../components/Keycap.js";
7
7
  import { useAppearanceState } from "../appearance/AppearanceProvider.js";
8
- import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
10
10
  import { AnimatePresence, motion, useIsPresent } from "motion/react";
11
11
  //#region src/app/ModalProvider.tsx
@@ -411,21 +411,119 @@ function ModalShell({ title, description, onClose, onBack, footer, children, siz
411
411
  ]
412
412
  });
413
413
  }
414
+ /** Whether the window is narrower than {@link SCREEN_NARROW_MAX}, followed while `watch` (no listener otherwise). */
415
+ function useNarrowWindow(watch) {
416
+ const query = `(max-width: 639px)`;
417
+ const [narrow, setNarrow] = useState(() => watch && typeof window !== "undefined" && window.matchMedia?.(query).matches === true);
418
+ useEffect(() => {
419
+ if (!watch || typeof window === "undefined" || !window.matchMedia) return void 0;
420
+ const list = window.matchMedia(query);
421
+ const update = () => setNarrow(list.matches);
422
+ update();
423
+ list.addEventListener("change", update);
424
+ return () => list.removeEventListener("change", update);
425
+ }, [watch, query]);
426
+ return watch && narrow;
427
+ }
428
+ /** Below this window width (px), a {@link ScreenShell} given `narrowPane` shows one pane at a time. */
429
+ const SCREEN_NARROW_MAX = 640;
414
430
  /**
415
431
  * Two-column full-window shell mirroring the chat layout: a sidebar-width
416
432
  * left column on the tray tone (traffic-light spacer, back button,
417
433
  * then whatever navigation the surface provides) and a main column with a
418
434
  * heading row over the content. Escape and the back button both call
419
- * `onClose`.
435
+ * `onClose`. On a narrow window with `narrowPane`, one pane at a time at full
436
+ * width: the left column, or the main one under a back button.
420
437
  *
421
438
  * @param props - The heading, the left column, the body and `onClose`.
422
439
  */
423
- function ScreenShell({ title, description, lead, screenLabel, onClose, aside, asideFooter, headerActions, children, className, style }) {
440
+ function ScreenShell({ title, description, lead, screenLabel, onClose, aside, asideFooter, headerActions, children, narrowPane, onNarrowBack, className, style }) {
424
441
  const modal = useModal();
425
442
  const labels = useLabels();
426
443
  const chrome = useContext(ChromeContext);
427
444
  const { sidebarWidth } = useAppearanceState();
445
+ const narrow = useNarrowWindow(narrowPane !== void 0);
428
446
  useDismissHandler(modal.setDismissHandler, onClose);
447
+ const backToApp = /* @__PURE__ */ jsxs("button", {
448
+ type: "button",
449
+ onClick: onClose,
450
+ "aria-label": labels.screenBack(screenLabel),
451
+ className: "zg-no-drag zg-menu-row zg-press-subtle !w-auto h-7 !min-h-0 !gap-1 !pl-1 !pr-1.5 font-medium",
452
+ children: [
453
+ /* @__PURE__ */ jsx("span", {
454
+ className: "i-ph-caret-left text-sm text-[var(--zg-text-muted)]",
455
+ "aria-hidden": true
456
+ }),
457
+ /* @__PURE__ */ jsx("span", {
458
+ className: "truncate",
459
+ children: screenLabel
460
+ }),
461
+ /* @__PURE__ */ jsx(Keycap, {
462
+ className: "ml-1.5",
463
+ children: labels.screenBackKey
464
+ })
465
+ ]
466
+ });
467
+ if (narrow) return /* @__PURE__ */ jsxs("div", {
468
+ className: `flex flex-col w-full h-full min-h-0 bg-[var(--zg-tray)]${className ? ` ${className}` : ""}`,
469
+ style,
470
+ children: [
471
+ /* @__PURE__ */ jsxs("div", {
472
+ className: "zg-drag shrink-0 flex items-center px-2",
473
+ style: { height: chromePx(chrome.top) },
474
+ children: [chrome.leading > 0 && /* @__PURE__ */ jsx("span", {
475
+ "aria-hidden": true,
476
+ className: "shrink-0",
477
+ style: { width: chromePx(chrome.leading) }
478
+ }), backToApp]
479
+ }),
480
+ /* @__PURE__ */ jsx("div", {
481
+ className: "shrink-0 px-3 pb-2",
482
+ children: aside.search
483
+ }),
484
+ narrowPane === "aside" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
485
+ className: "flex-1 min-h-0 flex flex-col px-2 pt-1",
486
+ children: aside.nav
487
+ }), asideFooter && /* @__PURE__ */ jsx("div", {
488
+ className: "shrink-0 px-2 pb-2",
489
+ children: asideFooter
490
+ })] }) : /* @__PURE__ */ jsxs("section", {
491
+ className: "flex-1 min-w-0 min-h-0 flex flex-col bg-[var(--zg-bg)]",
492
+ children: [/* @__PURE__ */ jsxs("header", {
493
+ className: "shrink-0 flex items-center gap-2 px-3 py-2.5 border-b border-[var(--zg-hairline)]",
494
+ children: [
495
+ onNarrowBack && /* @__PURE__ */ jsx(IconButton, {
496
+ icon: "i-ph-caret-left",
497
+ label: labels.screenNavBack(screenLabel),
498
+ onClick: onNarrowBack
499
+ }),
500
+ lead && /* @__PURE__ */ jsx("div", {
501
+ className: "shrink-0 flex",
502
+ children: lead
503
+ }),
504
+ /* @__PURE__ */ jsxs("div", {
505
+ className: "flex-1 min-w-0",
506
+ children: [/* @__PURE__ */ jsx("h2", {
507
+ id: MODAL_TITLE_ID,
508
+ className: "text-sm font-semibold leading-tight text-[var(--zg-text)] m-0 truncate",
509
+ children: title
510
+ }), description && /* @__PURE__ */ jsx("p", {
511
+ className: "text-xs leading-tight text-[var(--zg-text-muted)] mt-0.5 m-0 truncate",
512
+ children: description
513
+ })]
514
+ }),
515
+ headerActions && /* @__PURE__ */ jsx("div", {
516
+ className: "flex items-center gap-2 shrink-0",
517
+ children: headerActions
518
+ })
519
+ ]
520
+ }), /* @__PURE__ */ jsx("div", {
521
+ className: "flex-1 min-h-0 flex flex-col overflow-hidden",
522
+ children
523
+ })]
524
+ })
525
+ ]
526
+ });
429
527
  return /* @__PURE__ */ jsxs("div", {
430
528
  className: `flex w-full h-full min-h-0${className ? ` ${className}` : ""}`,
431
529
  style,
@@ -440,26 +538,7 @@ function ScreenShell({ title, description, lead, screenLabel, onClose, aside, as
440
538
  "aria-hidden": true,
441
539
  className: "shrink-0",
442
540
  style: { width: chromePx(chrome.leading) }
443
- }), /* @__PURE__ */ jsxs("button", {
444
- type: "button",
445
- onClick: onClose,
446
- "aria-label": labels.screenBack(screenLabel),
447
- className: "zg-no-drag zg-menu-row zg-press-subtle !w-auto h-7 !min-h-0 !gap-1 !pl-1 !pr-1.5 font-medium",
448
- children: [
449
- /* @__PURE__ */ jsx("span", {
450
- className: "i-ph-caret-left text-sm text-[var(--zg-text-muted)]",
451
- "aria-hidden": true
452
- }),
453
- /* @__PURE__ */ jsx("span", {
454
- className: "truncate",
455
- children: screenLabel
456
- }),
457
- /* @__PURE__ */ jsx(Keycap, {
458
- className: "ml-1.5",
459
- children: labels.screenBackKey
460
- })
461
- ]
462
- })]
541
+ }), backToApp]
463
542
  }),
464
543
  /* @__PURE__ */ jsx("div", {
465
544
  className: "zg-screen-toprow shrink-0 flex items-center px-3",
@@ -513,4 +592,4 @@ function ScreenShell({ title, description, lead, screenLabel, onClose, aside, as
513
592
  });
514
593
  }
515
594
  //#endregion
516
- export { MODAL_TITLE_ID, ModalProvider, ModalShell, ScreenShell, useModal, useOptionalModal };
595
+ export { MODAL_TITLE_ID, ModalProvider, ModalShell, SCREEN_NARROW_MAX, ScreenShell, useModal, useOptionalModal };
@@ -0,0 +1,33 @@
1
+ import { NoticeTone } from "../components/Notice.js";
2
+ import { CSSProperties, ReactNode } from "react";
3
+ //#region src/app/NoticeStack.d.ts
4
+ /** One notice to show. */
5
+ interface AppNotice {
6
+ /** How serious it is. */
7
+ tone: NoticeTone;
8
+ /** The message, worded for people (labels). */
9
+ message: string;
10
+ /** The raw words behind it (an exception's message): folded under Details. */
11
+ detail?: string;
12
+ }
13
+ /** Shows a notice in the app's stack. */
14
+ type Notify = (notice: AppNotice) => void;
15
+ /** Props for {@link NoticeStackProvider}. */
16
+ interface NoticeStackProviderProps {
17
+ /** The app. */
18
+ children: ReactNode;
19
+ /** Extra classes on the stack's region. */
20
+ className?: string;
21
+ /** Inline styles on the stack's region. */
22
+ style?: CSSProperties;
23
+ }
24
+ /**
25
+ * Provides {@link useNotify} to the components below and shows their notices, newest last.
26
+ *
27
+ * @param props - {@link NoticeStackProviderProps}.
28
+ */
29
+ declare function NoticeStackProvider({ children, className, style }: NoticeStackProviderProps): import("react").JSX.Element;
30
+ /** Shows a notice in the nearest {@link NoticeStackProvider}'s stack; outside one, a console warning. */
31
+ declare function useNotify(): Notify;
32
+ //#endregion
33
+ export { AppNotice, NoticeStackProvider, NoticeStackProviderProps, Notify, useNotify };
@@ -0,0 +1,90 @@
1
+ import { useLabels } from "../labels.js";
2
+ import { IconButton } from "../components/IconButton.js";
3
+ import { Notice } from "../components/Notice.js";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
6
+ //#region src/app/NoticeStack.tsx
7
+ /**
8
+ * The app's transient notices: what an action that has no surface of its own
9
+ * (a menu command, a background step) tells the user, as a stack of
10
+ * {@link Notice}s in a corner of the window. The in-app replacement for
11
+ * `window.alert()`.
12
+ *
13
+ * const notify = useNotify();
14
+ * notify({ tone: 'error', message: labels.moveSessionFailed, detail: errorMessage(err) });
15
+ *
16
+ * An error or a warning stays until dismissed. An info notice leaves after
17
+ * 6 s. `AppHostProvider` mounts one. An app that composes its providers by
18
+ * hand mounts `NoticeStackProvider` above them.
19
+ */
20
+ /** How long an info notice stays, in ms. */
21
+ const INFO_MS = 6e3;
22
+ const warnOutside = (notice) => {
23
+ console.warn(`[zidane-ui] ${notice.message}${notice.detail ? ` (${notice.detail})` : ""}`);
24
+ };
25
+ const NotifyContext = createContext(warnOutside);
26
+ /**
27
+ * Provides {@link useNotify} to the components below and shows their notices, newest last.
28
+ *
29
+ * @param props - {@link NoticeStackProviderProps}.
30
+ */
31
+ function NoticeStackProvider({ children, className, style }) {
32
+ const labels = useLabels();
33
+ const [shown, setShown] = useState([]);
34
+ const next = useRef(0);
35
+ const dismiss = useCallback((id) => setShown((all) => all.filter((n) => n.id !== id)), []);
36
+ const notify = useCallback((notice) => {
37
+ const id = next.current++;
38
+ setShown((all) => [...all, {
39
+ ...notice,
40
+ id
41
+ }]);
42
+ }, []);
43
+ return /* @__PURE__ */ jsxs(NotifyContext.Provider, {
44
+ value: notify,
45
+ children: [children, shown.length > 0 && /* @__PURE__ */ jsx("div", {
46
+ role: "region",
47
+ "aria-label": labels.noticeStack,
48
+ className: ["fixed bottom-3 right-3 z-zg-tooltip flex flex-col gap-2 w-[min(24rem,calc(100vw-1.5rem))]", className].filter(Boolean).join(" "),
49
+ style,
50
+ children: shown.map((n) => /* @__PURE__ */ jsx(StackedNotice, {
51
+ notice: n,
52
+ onDismiss: () => dismiss(n.id)
53
+ }, n.id))
54
+ })]
55
+ });
56
+ }
57
+ function StackedNotice({ notice, onDismiss }) {
58
+ const labels = useLabels();
59
+ const leave = useRef(onDismiss);
60
+ useEffect(() => {
61
+ leave.current = onDismiss;
62
+ });
63
+ useEffect(() => {
64
+ if (notice.tone !== "info") return void 0;
65
+ const timer = setTimeout(() => leave.current(), INFO_MS);
66
+ return () => clearTimeout(timer);
67
+ }, [notice.tone]);
68
+ return /* @__PURE__ */ jsx("div", {
69
+ className: "zg-float rounded-zg-md",
70
+ "data-notice-tone": notice.tone,
71
+ children: /* @__PURE__ */ jsx(Notice, {
72
+ tone: notice.tone,
73
+ ...notice.detail ? { detail: notice.detail } : {},
74
+ action: /* @__PURE__ */ jsx(IconButton, {
75
+ icon: "i-ph-x",
76
+ label: labels.noticeDismiss,
77
+ size: "sm",
78
+ onClick: onDismiss,
79
+ className: "ml-auto"
80
+ }),
81
+ children: notice.message
82
+ })
83
+ });
84
+ }
85
+ /** Shows a notice in the nearest {@link NoticeStackProvider}'s stack; outside one, a console warning. */
86
+ function useNotify() {
87
+ return useContext(NotifyContext);
88
+ }
89
+ //#endregion
90
+ export { NoticeStackProvider, useNotify };
@@ -1,5 +1,6 @@
1
1
  import { AppHostProvider, AppHostProviderProps, useAppHost } from "./AppHostProvider.js";
2
- import { LayerOptions, MODAL_TITLE_ID, ModalChromeInset, ModalContextValue, ModalOpenOptions, ModalProvider, ModalProviderProps, ModalScrimKind, ModalShell, ModalShellProps, ModalVariant, ScreenShell, ScreenShellProps, useModal, useOptionalModal } from "./ModalProvider.js";
2
+ import { LayerOptions, MODAL_TITLE_ID, ModalChromeInset, ModalContextValue, ModalOpenOptions, ModalProvider, ModalProviderProps, ModalScrimKind, ModalShell, ModalShellProps, ModalVariant, SCREEN_NARROW_MAX, ScreenShell, ScreenShellProps, useModal, useOptionalModal } from "./ModalProvider.js";
3
+ import { AppNotice, NoticeStackProvider, NoticeStackProviderProps, Notify, useNotify } from "./NoticeStack.js";
3
4
  import { useConfirm, useOptionalConfirm } from "./useConfirm.js";
4
5
  import { useResource } from "./useResource.js";
5
- export { AppHostProvider, AppHostProviderProps, LayerOptions, MODAL_TITLE_ID, ModalChromeInset, ModalContextValue, ModalOpenOptions, ModalProvider, ModalProviderProps, ModalScrimKind, ModalShell, ModalShellProps, ModalVariant, ScreenShell, ScreenShellProps, useAppHost, useConfirm, useModal, useOptionalConfirm, useOptionalModal, useResource };
6
+ export { AppHostProvider, AppHostProviderProps, AppNotice, LayerOptions, MODAL_TITLE_ID, ModalChromeInset, ModalContextValue, ModalOpenOptions, ModalProvider, ModalProviderProps, ModalScrimKind, ModalShell, ModalShellProps, ModalVariant, NoticeStackProvider, NoticeStackProviderProps, Notify, SCREEN_NARROW_MAX, ScreenShell, ScreenShellProps, useAppHost, useConfirm, useModal, useNotify, useOptionalConfirm, useOptionalModal, useResource };
package/dist/app/index.js CHANGED
@@ -1,5 +1,6 @@
1
+ import { NoticeStackProvider, useNotify } from "./NoticeStack.js";
1
2
  import { AppHostProvider, useAppHost } from "./AppHostProvider.js";
2
- import { MODAL_TITLE_ID, ModalProvider, ModalShell, ScreenShell, useModal, useOptionalModal } from "./ModalProvider.js";
3
+ import { MODAL_TITLE_ID, ModalProvider, ModalShell, SCREEN_NARROW_MAX, ScreenShell, useModal, useOptionalModal } from "./ModalProvider.js";
3
4
  import { useConfirm, useOptionalConfirm } from "./useConfirm.js";
4
5
  import { useResource } from "./useResource.js";
5
- export { AppHostProvider, MODAL_TITLE_ID, ModalProvider, ModalShell, ScreenShell, useAppHost, useConfirm, useModal, useOptionalConfirm, useOptionalModal, useResource };
6
+ export { AppHostProvider, MODAL_TITLE_ID, ModalProvider, ModalShell, NoticeStackProvider, SCREEN_NARROW_MAX, ScreenShell, useAppHost, useConfirm, useModal, useNotify, useOptionalConfirm, useOptionalModal, useResource };
@@ -106,7 +106,7 @@ interface SessionFilterMenuProps<V extends SessionView = SessionGroupBy> {
106
106
  project?: SessionProjectAxis;
107
107
  /** Last-activity filter axis: limit the list to sessions active within a window (`1d` to `30d`, or `all`). */
108
108
  activity?: SessionFilterAxis<SessionActivityFilter>;
109
- /** Sort axis: `alphabetical`, `createdTime`, or `recency`. */
109
+ /** Sort axis: `alphabetical`, `createdTime` (the default), `lastUserMessage`, or `recency`. */
110
110
  sort?: SessionFilterAxis<SessionSortBy>;
111
111
  /** More rows, each in the group its `placement` names, after the built-in ones. */
112
112
  extras?: readonly SessionFilterExtra[];
@@ -36,6 +36,7 @@ const ACTIVITIES = [
36
36
  const SORTS = [
37
37
  "alphabetical",
38
38
  "createdTime",
39
+ "lastUserMessage",
39
40
  "recency"
40
41
  ];
41
42
  const ALL_PROJECTS = "__all__";
@@ -99,7 +100,7 @@ function SessionFilterMenu({ view, status, project, activity, sort, extras = NO_
99
100
  [sort && /* @__PURE__ */ jsx(FilterSub, {
100
101
  label: labels.filterSort,
101
102
  value: labels.filterSorts[sort.value],
102
- atDefault: sort.value === "recency",
103
+ atDefault: sort.value === "createdTime",
103
104
  options: choices(sort.options ?? SORTS, labels.filterSorts),
104
105
  current: sort.value,
105
106
  onChange: (v) => sort.onChange(v)
@@ -1,4 +1,6 @@
1
1
  import { IconButton } from "../../components/IconButton.js";
2
+ import { Notice } from "../../components/Notice.js";
3
+ import { errorMessage } from "../../components/report-error.js";
2
4
  import { useLightbox } from "../../components/Lightbox.js";
3
5
  import { useChatLabels } from "../useChatLabels.js";
4
6
  import { AttachmentNotices, AttachmentTiles, attachmentLightboxItems } from "./attachments.js";
@@ -20,8 +22,7 @@ const Composer = forwardRef(function Composer(props, ref) {
20
22
  const labels = useChatLabels();
21
23
  const propsRef = useRef(props);
22
24
  propsRef.current = props;
23
- const runningPlaceholder = (props.delivery ?? "queue") === "steer" ? labels.composerPlaceholderSteer : labels.composerPlaceholderQueue;
24
- const placeholder = props.placeholder ?? (running ? runningPlaceholder : labels.composerPlaceholder);
25
+ const placeholder = props.placeholder ?? labels.composerPlaceholder;
25
26
  const placeholderRef = useRef(placeholder);
26
27
  placeholderRef.current = placeholder;
27
28
  const nameRef = useRef(props.ariaLabel ?? labels.composerLabel);
@@ -145,7 +146,7 @@ const Composer = forwardRef(function Composer(props, ref) {
145
146
  } catch (error) {
146
147
  restore();
147
148
  if (p.onError) p.onError(error);
148
- else setSendError(error instanceof Error && error.message ? error.message : String(error));
149
+ else setSendError(errorMessage(error));
149
150
  }
150
151
  }, [editor]);
151
152
  useLayoutEffect(() => {
@@ -338,11 +339,12 @@ const Composer = forwardRef(function Composer(props, ref) {
338
339
  })
339
340
  ]
340
341
  }),
341
- sendError && /* @__PURE__ */ jsx("p", {
342
- role: "alert",
343
- className: "m-0 px-4 pt-1.5 pb-0.5 text-zg-label text-zg-danger truncate",
344
- title: sendError,
345
- children: sendError
342
+ sendError && /* @__PURE__ */ jsx(Notice, {
343
+ tone: "error",
344
+ compact: true,
345
+ detail: sendError,
346
+ className: "mx-4 mt-1.5",
347
+ children: labels.composerSendFailed
346
348
  }),
347
349
  props.below,
348
350
  /* @__PURE__ */ jsx(SuggestionPopup, { state: suggest }),
@@ -1,3 +1,4 @@
1
+ import { Notice } from "../../components/Notice.js";
1
2
  import { useChatLabels } from "../useChatLabels.js";
2
3
  import { canJoinChain, lineupKeyOf, modelLineup, offCatalogRows, pickRefOf, pickerGroups, refKey, resolveChain, rowKey, unresolveChain, withPrimary } from "./model-catalog.js";
3
4
  import { layoutModelList } from "./model-list-layout.js";
@@ -285,15 +286,23 @@ function ModelChainList({ initialChain, catalog, loadError = null, onRetry, show
285
286
  inputRef
286
287
  }),
287
288
  /* @__PURE__ */ jsx("div", { className: "shrink-0 h-px bg-[var(--zg-hairline)]" }),
288
- loadError || notice ? /* @__PURE__ */ jsxs("div", {
289
+ loadError ? /* @__PURE__ */ jsx("div", {
290
+ className: "flex-1 min-h-0 flex flex-col items-center justify-center px-6 py-8",
291
+ children: /* @__PURE__ */ jsx(Notice, {
292
+ tone: "error",
293
+ detail: loadError,
294
+ action: onRetry && /* @__PURE__ */ jsx("button", {
295
+ type: "button",
296
+ className: "underline text-[var(--zg-text)] bg-transparent border-0 cursor-pointer",
297
+ onClick: onRetry,
298
+ children: labels.retry
299
+ }),
300
+ children: labels.modelsLoadError
301
+ })
302
+ }) : notice ? /* @__PURE__ */ jsx("div", {
289
303
  role: "status",
290
- className: `flex-1 min-h-0 flex flex-col items-center justify-center gap-2 px-6 py-8 text-center text-xs ${loadError ? "text-zg-danger" : "text-[var(--zg-text-muted)]"}`,
291
- children: [loadError ? labels.modelsLoadFailed(loadError) : notice, loadError && onRetry && /* @__PURE__ */ jsx("button", {
292
- type: "button",
293
- className: "underline text-[var(--zg-text)] bg-transparent border-0 cursor-pointer",
294
- onClick: onRetry,
295
- children: labels.retry
296
- })]
304
+ className: "flex-1 min-h-0 flex flex-col items-center justify-center gap-2 px-6 py-8 text-center text-xs text-[var(--zg-text-muted)]",
305
+ children: notice
297
306
  }) : /* @__PURE__ */ jsx(ModelChainRows, {
298
307
  layout,
299
308
  cursor,
@@ -1,3 +1,4 @@
1
+ import { Notice } from "../../components/Notice.js";
1
2
  import { useChatLabels } from "../useChatLabels.js";
2
3
  import { refKey, resolvePick, rowKey } from "./model-catalog.js";
3
4
  import { ModelProviderChip, ModelReasoning, ModelWindow } from "./ModelFacts.js";
@@ -34,8 +35,10 @@ function ModelChainTooltip({ chain, catalog, serving = null, forNextChat = false
34
35
  style,
35
36
  "data-testid": "model-chain-tooltip",
36
37
  children: [
37
- serving && /* @__PURE__ */ jsx("span", {
38
- className: "text-zg-warn leading-snug",
38
+ serving && /* @__PURE__ */ jsx(Notice, {
39
+ tone: "warning",
40
+ compact: true,
41
+ className: "leading-snug",
39
42
  children: labels.modelServing(primaryName, serving)
40
43
  }),
41
44
  forNextChat && /* @__PURE__ */ jsx("span", {
@@ -1,6 +1,7 @@
1
1
  import { DraftEnvironment, EnvironmentMachine } from "../../git/headless/environment.js";
2
- import { DraftFolderSource } from "../headless/draft-target.js";
2
+ import { DraftFolderSource, DraftPlaceIssue } from "../headless/draft-target.js";
3
3
  import { DraftRemoteClone } from "../../git/headless/remote-clone.js";
4
+ import { NewChatPlace } from "zidane/chat/pure";
4
5
  import { EnvironmentDescriptor } from "zidane/chat";
5
6
  //#region src/chat/composer/use-draft-target.d.ts
6
7
  /** A saved server a draft can run on. */
@@ -9,6 +10,8 @@ interface DraftServer {
9
10
  id: string;
10
11
  /** Its name. */
11
12
  name: string;
13
+ /** Its URL, kept with a default place for a device that has not saved it. */
14
+ url?: string;
12
15
  }
13
16
  /** What {@link useDraftTarget} reads from the app. */
14
17
  interface DraftTargetOptions {
@@ -34,6 +37,11 @@ interface DraftTargetOptions {
34
37
  * instead.
35
38
  */
36
39
  request?: DraftTargetRequest | null;
40
+ /**
41
+ * Where new chats start (the space's place, else the global one: `useNewSessionDefaults`). Applied to each new
42
+ * draft, before a request. Absent: this computer.
43
+ */
44
+ place?: NewChatPlace | null;
37
45
  }
38
46
  /** A draft target picked outside the composer. */
39
47
  interface DraftTargetRequest {
@@ -68,6 +76,11 @@ interface DraftTarget {
68
76
  server?: DraftServer;
69
77
  /** Runs the draft on a saved server (`LOCAL_HOST_KEY`: this computer). */
70
78
  setHostId(hostId: string): void;
79
+ /**
80
+ * Runs the draft on a host and one of its environment kinds in one step (a machine of another server picked
81
+ * from the where menu): the host's folder starts over, the kind is kept.
82
+ */
83
+ setPlace(hostId: string, environment: string): void;
71
84
  /** The server's folder (`null`: its first root). */
72
85
  remoteFolder: string | null;
73
86
  /** Picks the server's folder. */
@@ -98,6 +111,12 @@ interface DraftTarget {
98
111
  setMachineFolder(folder: string | null): void;
99
112
  /** The host the machine's folders are browsed through. */
100
113
  machineHost: string;
114
+ /** Why the draft cannot use the default place as it is (until dismissed or the next draft). */
115
+ placeIssue: DraftPlaceIssue | null;
116
+ /** Hides {@link DraftTarget.placeIssue}. */
117
+ dismissPlaceIssue(): void;
118
+ /** The draft's pick as a place: what "Use for new chats" saves. */
119
+ here: NewChatPlace;
101
120
  /** Why the last new chat could not be created (the prompt is back in the box). */
102
121
  error: string | null;
103
122
  /** Shows or clears {@link DraftTarget.error}. */