@agent-native/core 0.97.0 → 0.98.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 (844) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +32 -0
  3. package/corpus/core/docs/content/authentication.mdx +3 -3
  4. package/corpus/core/docs/content/doctor.mdx +170 -0
  5. package/corpus/core/docs/content/external-agents.mdx +8 -7
  6. package/corpus/core/docs/content/locales/ar-SA/authentication.mdx +2 -2
  7. package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +8 -7
  8. package/corpus/core/docs/content/locales/ar-SA/mcp-protocol.mdx +1 -1
  9. package/corpus/core/docs/content/locales/ar-SA/security.mdx +2 -0
  10. package/corpus/core/docs/content/locales/de-DE/authentication.mdx +1 -1
  11. package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +8 -7
  12. package/corpus/core/docs/content/locales/de-DE/mcp-protocol.mdx +1 -1
  13. package/corpus/core/docs/content/locales/de-DE/security.mdx +2 -0
  14. package/corpus/core/docs/content/locales/es-ES/authentication.mdx +2 -2
  15. package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +8 -7
  16. package/corpus/core/docs/content/locales/es-ES/mcp-protocol.mdx +1 -1
  17. package/corpus/core/docs/content/locales/es-ES/security.mdx +2 -0
  18. package/corpus/core/docs/content/locales/fr-FR/authentication.mdx +1 -1
  19. package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +8 -7
  20. package/corpus/core/docs/content/locales/fr-FR/mcp-protocol.mdx +1 -1
  21. package/corpus/core/docs/content/locales/fr-FR/security.mdx +2 -0
  22. package/corpus/core/docs/content/locales/hi-IN/authentication.mdx +2 -2
  23. package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +8 -7
  24. package/corpus/core/docs/content/locales/hi-IN/mcp-protocol.mdx +1 -1
  25. package/corpus/core/docs/content/locales/hi-IN/security.mdx +2 -0
  26. package/corpus/core/docs/content/locales/ja-JP/authentication.mdx +2 -2
  27. package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +8 -7
  28. package/corpus/core/docs/content/locales/ja-JP/mcp-protocol.mdx +1 -1
  29. package/corpus/core/docs/content/locales/ja-JP/security.mdx +2 -0
  30. package/corpus/core/docs/content/locales/ko-KR/authentication.mdx +2 -2
  31. package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +8 -7
  32. package/corpus/core/docs/content/locales/ko-KR/mcp-protocol.mdx +1 -1
  33. package/corpus/core/docs/content/locales/ko-KR/security.mdx +2 -0
  34. package/corpus/core/docs/content/locales/pt-BR/authentication.mdx +2 -2
  35. package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +8 -7
  36. package/corpus/core/docs/content/locales/pt-BR/mcp-protocol.mdx +1 -1
  37. package/corpus/core/docs/content/locales/pt-BR/security.mdx +2 -0
  38. package/corpus/core/docs/content/locales/zh-CN/authentication.mdx +2 -2
  39. package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +8 -7
  40. package/corpus/core/docs/content/locales/zh-CN/mcp-protocol.mdx +1 -1
  41. package/corpus/core/docs/content/locales/zh-CN/security.mdx +2 -0
  42. package/corpus/core/docs/content/locales/zh-TW/authentication.mdx +2 -2
  43. package/corpus/core/docs/content/locales/zh-TW/external-agents.mdx +8 -7
  44. package/corpus/core/docs/content/locales/zh-TW/mcp-protocol.mdx +1 -1
  45. package/corpus/core/docs/content/locales/zh-TW/security.mdx +2 -0
  46. package/corpus/core/docs/content/mcp-protocol.mdx +1 -1
  47. package/corpus/core/docs/content/security.mdx +2 -0
  48. package/corpus/core/package.json +5 -1
  49. package/corpus/core/scripts/finalize-build.mjs +63 -3
  50. package/corpus/core/scripts/materialize-source-corpus.mjs +101 -15
  51. package/corpus/core/src/action.ts +42 -0
  52. package/corpus/core/src/agent/engine/builder-engine.ts +3 -0
  53. package/corpus/core/src/agent/engine/context-directives-transform.ts +69 -0
  54. package/corpus/core/src/agent/engine/continuation-dispatch-retry.ts +168 -0
  55. package/corpus/core/src/agent/engine/tool-call-journal-seed.ts +85 -0
  56. package/corpus/core/src/agent/production-agent.ts +129 -244
  57. package/corpus/core/src/cli/doctor.ts +9 -3
  58. package/corpus/core/src/cli/plan-local.ts +10 -2
  59. package/corpus/core/src/cli/skills-content/assets-skill.ts +83 -0
  60. package/corpus/core/src/cli/skills-content/canvas.ts +153 -0
  61. package/corpus/core/src/cli/skills-content/connection.ts +52 -0
  62. package/corpus/core/src/cli/skills-content/content-skill.ts +109 -0
  63. package/corpus/core/src/cli/skills-content/design-exploration-skill.ts +118 -0
  64. package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +228 -0
  65. package/corpus/core/src/cli/skills-content/document-quality.ts +196 -0
  66. package/corpus/core/src/cli/skills-content/exemplar.ts +69 -0
  67. package/corpus/core/src/cli/skills-content/help.ts +77 -0
  68. package/corpus/core/src/cli/skills-content/index.ts +22 -0
  69. package/corpus/core/src/cli/skills-content/local-files.ts +95 -0
  70. package/corpus/core/src/cli/skills-content/plan-setup-auth.ts +80 -0
  71. package/corpus/core/src/cli/skills-content/visual-plan-skill.ts +470 -0
  72. package/corpus/core/src/cli/skills-content/visual-recap-skill.ts +547 -0
  73. package/corpus/core/src/cli/skills-content/visualize-repo-skill.ts +93 -0
  74. package/corpus/core/src/cli/skills-content/wireframe.ts +349 -0
  75. package/corpus/core/src/cli/skills.ts +27 -2733
  76. package/corpus/core/src/client/AgentPanel.tsx +6 -5
  77. package/corpus/core/src/client/CommandMenu.tsx +16 -5
  78. package/corpus/core/src/client/FeedbackButton.tsx +2 -2
  79. package/corpus/core/src/client/app-providers.tsx +18 -5
  80. package/corpus/core/src/client/chat/tool-call-display.tsx +3 -3
  81. package/corpus/core/src/client/composer/PastedTextChip.tsx +1 -1
  82. package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +143 -45
  83. package/corpus/core/src/client/composer/TiptapComposer.tsx +1 -1
  84. package/corpus/core/src/client/composer/VoiceButton.tsx +21 -5
  85. package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +107 -10
  86. package/corpus/core/src/client/context-xray/ContextXRayPanel.tsx +5 -2
  87. package/corpus/core/src/client/extensions/ExtensionEditor.tsx +37 -4
  88. package/corpus/core/src/client/extensions/ExtensionQueryErrorState.tsx +47 -0
  89. package/corpus/core/src/client/extensions/ExtensionSlot.tsx +39 -10
  90. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +44 -6
  91. package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +12 -3
  92. package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +49 -11
  93. package/corpus/core/src/client/index.ts +0 -13
  94. package/corpus/core/src/client/progress/RunsTray.tsx +10 -3
  95. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +7 -0
  96. package/corpus/core/src/client/settings/useBuilderStatus.ts +6 -0
  97. package/corpus/core/src/client/tool-cells/EditCell.tsx +19 -16
  98. package/corpus/core/src/client/tool-cells/FilesChangedSummary.tsx +26 -23
  99. package/corpus/core/src/client/tool-cells/WriteCell.tsx +19 -16
  100. package/corpus/core/src/client/visual-style-controls.tsx +1 -1
  101. package/corpus/core/src/deploy/build.ts +36 -14
  102. package/corpus/core/src/integrations/google-docs-poller.ts +23 -2
  103. package/corpus/core/src/integrations/plugin.ts +10 -0
  104. package/corpus/core/src/integrations/webhook-handler.ts +27 -2
  105. package/corpus/core/src/jobs/scheduler.ts +28 -2
  106. package/corpus/core/src/localization/default-messages.ts +8 -1
  107. package/corpus/core/src/mcp/oauth-token.ts +6 -1
  108. package/corpus/core/src/observability/routes.ts +36 -0
  109. package/corpus/core/src/observability/sentiment.ts +261 -0
  110. package/corpus/core/src/observability/store.ts +23 -0
  111. package/corpus/core/src/observability/traces.ts +49 -63
  112. package/corpus/core/src/observability/tracking-identity.ts +55 -0
  113. package/corpus/core/src/observability/types.ts +13 -0
  114. package/corpus/core/src/secrets/storage.ts +67 -3
  115. package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +199 -0
  116. package/corpus/core/src/server/agent-chat/browser-team-tools.ts +510 -0
  117. package/corpus/core/src/server/agent-chat/context-tools.ts +595 -0
  118. package/corpus/core/src/server/agent-chat/framework-prompts.ts +470 -0
  119. package/corpus/core/src/server/agent-chat/lazy-fs.ts +11 -0
  120. package/corpus/core/src/server/agent-chat/mcp-glue.ts +91 -0
  121. package/corpus/core/src/server/agent-chat/plugin-options.ts +350 -0
  122. package/corpus/core/src/server/agent-chat/process-run-failure.ts +62 -0
  123. package/corpus/core/src/server/agent-chat/prompt-resources.ts +688 -0
  124. package/corpus/core/src/server/agent-chat/recurring-jobs-runtime.ts +80 -0
  125. package/corpus/core/src/server/agent-chat/request-surface.ts +71 -0
  126. package/corpus/core/src/server/agent-chat/run-code-tools.ts +67 -0
  127. package/corpus/core/src/server/agent-chat/script-entries.ts +779 -0
  128. package/corpus/core/src/server/agent-chat/shared-thread.ts +301 -0
  129. package/corpus/core/src/server/agent-chat/skill-frontmatter.ts +41 -0
  130. package/corpus/core/src/server/agent-chat-plugin.ts +364 -4182
  131. package/corpus/core/src/server/agent-teams.ts +26 -3
  132. package/corpus/core/src/server/auth.ts +55 -57
  133. package/corpus/core/src/server/credential-provider.ts +22 -25
  134. package/corpus/core/src/server/edge.ts +1 -0
  135. package/corpus/core/src/server/onboarding-html.ts +1 -16
  136. package/corpus/core/src/server/realtime-voice.ts +40 -5
  137. package/corpus/core/src/server/request-origin.ts +6 -2
  138. package/corpus/core/src/server/ssr-handler.ts +55 -2
  139. package/corpus/core/src/sharing/access.ts +155 -11
  140. package/corpus/core/src/sharing/registry.ts +7 -0
  141. package/corpus/core/src/styles/agent-native.css +15 -14
  142. package/corpus/core/src/templates/default/.agents/skills/frontend-design/SKILL.md +1 -1
  143. package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +6 -0
  144. package/corpus/core/src/templates/default/app/i18n/de-DE.ts +6 -0
  145. package/corpus/core/src/templates/default/app/i18n/en-US.ts +6 -0
  146. package/corpus/core/src/templates/default/app/i18n/es-ES.ts +6 -0
  147. package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +6 -0
  148. package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +6 -0
  149. package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +6 -0
  150. package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +6 -0
  151. package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +6 -0
  152. package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +6 -0
  153. package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +6 -0
  154. package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +27 -29
  155. package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +2 -1
  156. package/corpus/core/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -1
  157. package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +32 -0
  158. package/corpus/core/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +25 -0
  159. package/corpus/core/src/templates/workspace-core/src/server/index.ts +4 -2
  160. package/corpus/core/src/testing.ts +26 -0
  161. package/corpus/core/src/triggers/dispatcher.ts +23 -2
  162. package/corpus/core/src/vite/client.ts +126 -2
  163. package/corpus/core/tsconfig.cli.json +1 -1
  164. package/corpus/core/tsconfig.json +5 -1
  165. package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +2 -2
  166. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +1 -1
  167. package/corpus/templates/analytics/AGENTS.md +19 -6
  168. package/corpus/templates/analytics/actions/install-dashboard-template.ts +79 -43
  169. package/corpus/templates/analytics/actions/list-explorer-dashboards.ts +3 -3
  170. package/corpus/templates/analytics/actions/list-sql-dashboards.ts +8 -3
  171. package/corpus/templates/analytics/actions/rename-analysis.ts +8 -2
  172. package/corpus/templates/analytics/actions/rename-dashboard.ts +8 -7
  173. package/corpus/templates/analytics/actions/view-screen.ts +4 -23
  174. package/corpus/templates/analytics/app/components/ResourceLoadError.tsx +42 -0
  175. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +85 -70
  176. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +107 -89
  177. package/corpus/templates/analytics/app/components/layout/SidebarLoadError.tsx +24 -0
  178. package/corpus/templates/analytics/app/hooks/use-dashboard-views.ts +15 -5
  179. package/corpus/templates/analytics/app/i18n/zh-TW.ts +4 -0
  180. package/corpus/templates/analytics/app/i18n-data.ts +40 -0
  181. package/corpus/templates/analytics/app/pages/Settings.tsx +6 -2
  182. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/SqlPreview.tsx +36 -20
  183. package/corpus/templates/analytics/app/pages/adhoc/explorer/index.tsx +34 -20
  184. package/corpus/templates/analytics/app/pages/adhoc/explorer/use-explorer-config.ts +42 -41
  185. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +43 -36
  186. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/ViewsMenu.tsx +11 -2
  187. package/corpus/templates/analytics/app/root.tsx +13 -1
  188. package/corpus/templates/analytics/app/routes/_index.tsx +14 -2
  189. package/corpus/templates/analytics/changelog/2026-07-03-agent-llm-observability-dashboard.md +1 -1
  190. package/corpus/templates/analytics/changelog/2026-07-11-agent-feedback-sentiment-dashboard.md +6 -0
  191. package/corpus/templates/analytics/changelog/2026-07-11-analytics-chats-now-start-faster-by-loading-metric-definitio.md +6 -0
  192. package/corpus/templates/analytics/changelog/2026-07-11-command-and-sql-previews-now-respond-without-lag.md +6 -0
  193. package/corpus/templates/analytics/changelog/2026-07-11-command-search-now-reports-loading-failures-and-lets-you-ret.md +6 -0
  194. package/corpus/templates/analytics/changelog/2026-07-11-dashboard-navigation-now-loads-faster-and-reports-request-fa.md +6 -0
  195. package/corpus/templates/analytics/changelog/2026-07-11-inferred-message-sentiment-dashboard.md +6 -0
  196. package/corpus/templates/analytics/changelog/2026-07-11-microphone-settings-from-realtime-voice-mode-now-open-the-vo.md +6 -0
  197. package/corpus/templates/analytics/changelog/2026-07-11-more-dashboard-edit-paths-are-now-safe-against-simultaneous-.md +6 -0
  198. package/corpus/templates/analytics/changelog/2026-07-11-renaming-a-dashboard-is-now-safe-against-simultaneous-agent-.md +6 -0
  199. package/corpus/templates/analytics/changelog/2026-07-11-renaming-an-analysis-is-now-safe-against-simultaneous-edits.md +6 -0
  200. package/corpus/templates/analytics/changelog/2026-07-11-workspace-mounted-analytics-now-opens-ask-reliably-and-route.md +6 -0
  201. package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +37 -3
  202. package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +339 -1
  203. package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +1 -24
  204. package/corpus/templates/analytics/server/lib/dashboard-seeds.ts +0 -5
  205. package/corpus/templates/analytics/server/lib/dashboards-store.ts +289 -20
  206. package/corpus/templates/analytics/server/lib/data-dictionary-context.ts +106 -34
  207. package/corpus/templates/analytics/server/lib/demo-dashboards.ts +4 -1
  208. package/corpus/templates/analytics/server/plugins/agent-chat.ts +11 -39
  209. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +1 -1
  210. package/corpus/templates/assets/app/components/create/RecentDraftsSection.tsx +30 -4
  211. package/corpus/templates/assets/app/routes/library.tsx +49 -5
  212. package/corpus/templates/assets/changelog/2026-07-11-library-load-failures-now-show-a-retry-action.md +6 -0
  213. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +1 -1
  214. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +1 -1
  215. package/corpus/templates/calendar/.env.example +5 -0
  216. package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +2 -2
  217. package/corpus/templates/calendar/app/i18n/zh-TW.ts +2 -0
  218. package/corpus/templates/calendar/app/i18n-data.ts +20 -0
  219. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +37 -1
  220. package/corpus/templates/calendar/app/pages/BookingsList.tsx +20 -3
  221. package/corpus/templates/calendar/changelog/2026-07-11-booking-load-failures-now-show-a-retry-action.md +6 -0
  222. package/corpus/templates/calendar/changelog/2026-07-11-event-cards-give-subtle-press-feedback-and-smoother-hover.md +6 -0
  223. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +1 -1
  224. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +1 -1
  225. package/corpus/templates/clips/actions/decline-invite.ts +8 -0
  226. package/corpus/templates/clips/app/components/library/folder-tree.tsx +209 -187
  227. package/corpus/templates/clips/app/components/meetings/meeting-card.tsx +2 -2
  228. package/corpus/templates/clips/app/components/player/reactions-tray.tsx +17 -5
  229. package/corpus/templates/clips/app/components/player/scrubber.tsx +5 -3
  230. package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +2 -2
  231. package/corpus/templates/clips/app/components/workspace/insights-hub.tsx +119 -95
  232. package/corpus/templates/clips/app/global.css +45 -0
  233. package/corpus/templates/clips/app/root.tsx +4 -0
  234. package/corpus/templates/clips/app/routes/_app.notifications.tsx +23 -2
  235. package/corpus/templates/clips/app/routes/_app.trash.tsx +24 -2
  236. package/corpus/templates/clips/changelog/2026-07-11-controls-and-folders-now-move-more-smoothly.md +6 -0
  237. package/corpus/templates/clips/changelog/2026-07-11-declining-an-invitation-now-requires-being-its-recipient.md +6 -0
  238. package/corpus/templates/clips/changelog/2026-07-11-recording-overlays-are-lighter-weight-and-no-longer-cause-pa.md +6 -0
  239. package/corpus/templates/clips/changelog/2026-07-11-workspace-load-failures-now-show-a-retry-action.md +6 -0
  240. package/corpus/templates/clips/chrome-extension/src/overlay.css +34 -5
  241. package/corpus/templates/clips/chrome-extension/src/styles.css +2 -2
  242. package/corpus/templates/clips/desktop/src/styles.css +71 -26
  243. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +1 -1
  244. package/corpus/templates/content/actions/move-document.ts +34 -18
  245. package/corpus/templates/content/app/components/QueryErrorState.tsx +39 -0
  246. package/corpus/templates/content/app/components/editor/LinkHoverPreview.tsx +1 -1
  247. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +225 -1435
  248. package/corpus/templates/content/app/components/editor/database/GalleryView.tsx +368 -0
  249. package/corpus/templates/content/app/components/editor/database/ListView.tsx +353 -0
  250. package/corpus/templates/content/app/components/editor/database/TimelineView.tsx +580 -0
  251. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -2
  252. package/corpus/templates/content/app/global.css +19 -19
  253. package/corpus/templates/content/app/root.tsx +2 -2
  254. package/corpus/templates/content/app/routes/_app._index.tsx +11 -1
  255. package/corpus/templates/content/changelog/2026-07-11-document-load-failures-now-show-a-retry-action.md +6 -0
  256. package/corpus/templates/content/changelog/2026-07-11-editor-toggle-feedback-now-feels-more-responsive.md +6 -0
  257. package/corpus/templates/content/changelog/2026-07-11-moving-documents-at-the-same-time-no-longer-scrambles-their-.md +6 -0
  258. package/corpus/templates/content/changelog/2026-07-11-public-document-chats-now-start-faster-while-keeping-full-do.md +6 -0
  259. package/corpus/templates/content/changelog/2026-07-11-reopening-a-comment-now-uses-consistent-permissions-everywhe.md +6 -0
  260. package/corpus/templates/content/changelog/2026-07-11-sidebar-resizing-now-tracks-your-cursor-instantly-instead-of.md +6 -0
  261. package/corpus/templates/content/server/lib/public-documents.ts +47 -10
  262. package/corpus/templates/content/server/routes/api/comments/[id].patch.ts +24 -24
  263. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +1 -1
  264. package/corpus/templates/design/app/components/QueryErrorState.tsx +24 -0
  265. package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +1 -1
  266. package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +5 -2
  267. package/corpus/templates/design/app/components/design/EditPanel.tsx +326 -319
  268. package/corpus/templates/design/app/components/design/LayersPanel.tsx +198 -193
  269. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +11 -4
  270. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +1 -1
  271. package/corpus/templates/design/app/components/layout/Layout.tsx +1 -1
  272. package/corpus/templates/design/app/pages/DesignSystems.tsx +7 -1
  273. package/corpus/templates/design/app/pages/Index.tsx +14 -2
  274. package/corpus/templates/design/app/pages/Present.tsx +16 -3
  275. package/corpus/templates/design/app/pages/Templates.tsx +10 -4
  276. package/corpus/templates/design/app/pages/design-editor/canvas-primitive-insert.ts +484 -0
  277. package/corpus/templates/design/app/pages/design-editor/clone-and-pen-edit.ts +378 -0
  278. package/corpus/templates/design/app/pages/design-editor/design-data-geometry-utils.ts +138 -0
  279. package/corpus/templates/design/app/pages/design-editor/dom-utils.ts +15 -0
  280. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +180 -0
  281. package/corpus/templates/design/app/pages/design-editor/html-layer-positioning.ts +226 -0
  282. package/corpus/templates/design/app/pages/design-editor/png-export-render.ts +348 -0
  283. package/corpus/templates/design/app/pages/design-editor/screen-command-utils.ts +160 -0
  284. package/corpus/templates/design/app/pages/design-editor/text-edit-utils.ts +238 -0
  285. package/corpus/templates/design/app/pages/design-editor/tool-state.ts +23 -1
  286. package/corpus/templates/design/app/pages/design-editor/types.ts +25 -0
  287. package/corpus/templates/design/app/root.tsx +10 -1
  288. package/corpus/templates/design/changelog/2026-07-11-canvas-context-menus-now-open-without-motion-jitter.md +6 -0
  289. package/corpus/templates/design/changelog/2026-07-11-design-load-failures-now-show-a-retry-action.md +6 -0
  290. package/corpus/templates/design/changelog/2026-07-11-inspector-tooltips-appear-instantly-as-you-sweep-across-icon.md +6 -0
  291. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +1 -1
  292. package/corpus/templates/dispatch/app/i18n/zh-TW.ts +10 -0
  293. package/corpus/templates/dispatch/app/i18n-data.ts +123 -0
  294. package/corpus/templates/dispatch/app/routes/integrations.tsx +163 -144
  295. package/corpus/templates/dispatch/changelog/2026-07-11-dispatch-mcp-connections-now-start-with-safer-app-access-and.md +6 -0
  296. package/corpus/templates/dispatch/changelog/2026-07-11-overview-and-chat-now-share-a-cleaner-more-stable-flow.md +6 -0
  297. package/corpus/templates/dispatch/changelog/2026-07-11-query-errors-now-show-a-retry-option.md +6 -0
  298. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +1 -1
  299. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +3 -3
  300. package/corpus/templates/forms/app/root.tsx +34 -8
  301. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +1 -1
  302. package/corpus/templates/macros/app/components/DailyProgress.tsx +25 -5
  303. package/corpus/templates/macros/app/components/QueryErrorState.tsx +31 -0
  304. package/corpus/templates/macros/app/components/WeightTracker.tsx +5 -1
  305. package/corpus/templates/macros/app/components/ui/button.tsx +1 -1
  306. package/corpus/templates/macros/app/components/ui/progress.tsx +1 -1
  307. package/corpus/templates/macros/app/components/ui/tabs.tsx +1 -1
  308. package/corpus/templates/macros/app/i18n/ar-SA.ts +2 -0
  309. package/corpus/templates/macros/app/i18n/de-DE.ts +2 -0
  310. package/corpus/templates/macros/app/i18n/en-US.ts +2 -0
  311. package/corpus/templates/macros/app/i18n/es-ES.ts +2 -0
  312. package/corpus/templates/macros/app/i18n/fr-FR.ts +2 -0
  313. package/corpus/templates/macros/app/i18n/hi-IN.ts +2 -0
  314. package/corpus/templates/macros/app/i18n/ja-JP.ts +2 -0
  315. package/corpus/templates/macros/app/i18n/ko-KR.ts +2 -0
  316. package/corpus/templates/macros/app/i18n/pt-BR.ts +2 -0
  317. package/corpus/templates/macros/app/i18n/zh-CN.ts +2 -0
  318. package/corpus/templates/macros/app/i18n/zh-TW.ts +2 -0
  319. package/corpus/templates/macros/app/routes/_index.tsx +22 -12
  320. package/corpus/templates/macros/app/routes/analytics.tsx +31 -10
  321. package/corpus/templates/macros/changelog/2026-07-11-daily-tracking-now-loads-and-updates-more-quickly.md +6 -0
  322. package/corpus/templates/macros/changelog/2026-07-11-data-load-failures-now-show-a-clear-error-with-a-retry-actio.md +6 -0
  323. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +1 -1
  324. package/corpus/templates/mail/.env.example +16 -11
  325. package/corpus/templates/mail/actions/list-emails.ts +39 -35
  326. package/corpus/templates/mail/app/components/email/ComposeModal.tsx +58 -6
  327. package/corpus/templates/mail/app/components/email/EmailListItem.tsx +35 -2
  328. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +113 -104
  329. package/corpus/templates/mail/app/root.tsx +8 -10
  330. package/corpus/templates/mail/changelog/2026-07-11-compose-and-navigation-motion-now-feel-faster-and-smoother.md +6 -0
  331. package/corpus/templates/mail/changelog/2026-07-11-swipe-to-archive-or-snooze-now-responds-to-quick-flicks-not-.md +6 -0
  332. package/corpus/templates/mail/changelog/2026-07-11-the-assistant-now-sees-the-same-inbox-you-do-snoozed-mail-st.md +6 -0
  333. package/corpus/templates/mail/server/handlers/emails.ts +25 -69
  334. package/corpus/templates/mail/server/lib/list-inbox-emails.ts +169 -0
  335. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +1 -1
  336. package/corpus/templates/plan/.env.example +4 -0
  337. package/corpus/templates/plan/actions/create-plan-design.ts +89 -81
  338. package/corpus/templates/plan/actions/create-prototype-plan.ts +72 -59
  339. package/corpus/templates/plan/actions/create-ui-plan.ts +70 -55
  340. package/corpus/templates/plan/actions/create-visual-plan.ts +65 -51
  341. package/corpus/templates/plan/actions/update-local-plan-folder.ts +43 -30
  342. package/corpus/templates/plan/actions/update-visual-plan.ts +81 -64
  343. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +17 -0
  344. package/corpus/templates/plan/app/components/ui/tabs.tsx +1 -1
  345. package/corpus/templates/plan/app/i18n/ar-SA.ts +10 -0
  346. package/corpus/templates/plan/app/i18n/de-DE.ts +10 -0
  347. package/corpus/templates/plan/app/i18n/en-US.ts +10 -0
  348. package/corpus/templates/plan/app/i18n/es-ES.ts +10 -0
  349. package/corpus/templates/plan/app/i18n/fr-FR.ts +10 -0
  350. package/corpus/templates/plan/app/i18n/hi-IN.ts +10 -0
  351. package/corpus/templates/plan/app/i18n/ja-JP.ts +10 -0
  352. package/corpus/templates/plan/app/i18n/ko-KR.ts +10 -0
  353. package/corpus/templates/plan/app/i18n/pt-BR.ts +10 -0
  354. package/corpus/templates/plan/app/i18n/zh-CN.ts +10 -0
  355. package/corpus/templates/plan/app/i18n/zh-TW.ts +10 -0
  356. package/corpus/templates/plan/app/lib/plan-local-bridge.ts +80 -1
  357. package/corpus/templates/plan/app/pages/PlansPage.tsx +152 -4
  358. package/corpus/templates/plan/app/root.tsx +11 -0
  359. package/corpus/templates/plan/changelog/2026-07-11-local-plans-now-explain-and-recover-from-browser-permission-.md +6 -0
  360. package/corpus/templates/plan/changelog/2026-07-11-plan-edits-now-save-atomically-and-can-no-longer-partially-a.md +6 -0
  361. package/corpus/templates/plan/changelog/2026-07-11-plan-lists-now-show-a-clear-error-with-a-retry-action-when-t.md +6 -0
  362. package/corpus/templates/plan/shared/plan-content.ts +546 -260
  363. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +1 -1
  364. package/corpus/templates/slides/actions/delete-slide-comment.ts +49 -0
  365. package/corpus/templates/slides/actions/update-slide-comment.ts +93 -0
  366. package/corpus/templates/slides/actions/view-screen.ts +14 -6
  367. package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +33 -10
  368. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +1 -1
  369. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +1 -1
  370. package/corpus/templates/slides/app/components/editor/GenerateSlidesDialog.tsx +2 -2
  371. package/corpus/templates/slides/app/components/presentation/PresentationView.tsx +4 -2
  372. package/corpus/templates/slides/app/components/visual-editor/CanvasCommentPins.tsx +4 -3
  373. package/corpus/templates/slides/app/context/DeckContext.tsx +9 -0
  374. package/corpus/templates/slides/app/i18n/ar-SA.ts +6 -0
  375. package/corpus/templates/slides/app/i18n/de-DE.ts +6 -0
  376. package/corpus/templates/slides/app/i18n/en-US.ts +6 -0
  377. package/corpus/templates/slides/app/i18n/es-ES.ts +6 -0
  378. package/corpus/templates/slides/app/i18n/fr-FR.ts +6 -0
  379. package/corpus/templates/slides/app/i18n/hi-IN.ts +6 -0
  380. package/corpus/templates/slides/app/i18n/ja-JP.ts +6 -0
  381. package/corpus/templates/slides/app/i18n/ko-KR.ts +6 -0
  382. package/corpus/templates/slides/app/i18n/pt-BR.ts +6 -0
  383. package/corpus/templates/slides/app/i18n/zh-CN.ts +5 -0
  384. package/corpus/templates/slides/app/i18n/zh-TW.ts +5 -0
  385. package/corpus/templates/slides/app/pages/DesignSystems.tsx +23 -2
  386. package/corpus/templates/slides/app/pages/Index.tsx +29 -1
  387. package/corpus/templates/slides/changelog/2026-07-11-comment-load-failures-now-show-a-retry-action-instead-of-say.md +6 -0
  388. package/corpus/templates/slides/changelog/2026-07-11-comment-pins-now-clear-with-a-faster-smoother-confirmation.md +6 -0
  389. package/corpus/templates/slides/changelog/2026-07-11-deck-and-design-system-load-failures-now-show-a-retry-action.md +6 -0
  390. package/corpus/templates/slides/changelog/2026-07-11-editor-toggles-and-toolbar-menus-now-animate-smoothly.md +6 -0
  391. package/corpus/templates/slides/changelog/2026-07-11-the-assistant-can-now-resolve-reopen-and-delete-slide-commen.md +6 -0
  392. package/corpus/templates/slides/changelog/2026-07-11-viewing-slides-no-longer-loads-every-deck-s-full-contents-in.md +6 -0
  393. package/corpus/templates/slides/server/routes/api/comments/[id].delete.ts +29 -48
  394. package/corpus/templates/slides/server/routes/api/comments/[id].patch.ts +29 -65
  395. package/dist/action.d.ts +23 -0
  396. package/dist/action.d.ts.map +1 -1
  397. package/dist/action.js +13 -0
  398. package/dist/action.js.map +1 -1
  399. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  400. package/dist/agent/engine/builder-engine.js +3 -0
  401. package/dist/agent/engine/builder-engine.js.map +1 -1
  402. package/dist/agent/engine/context-directives-transform.d.ts +25 -0
  403. package/dist/agent/engine/context-directives-transform.d.ts.map +1 -0
  404. package/dist/agent/engine/context-directives-transform.js +53 -0
  405. package/dist/agent/engine/context-directives-transform.js.map +1 -0
  406. package/dist/agent/engine/continuation-dispatch-retry.d.ts +40 -0
  407. package/dist/agent/engine/continuation-dispatch-retry.d.ts.map +1 -0
  408. package/dist/agent/engine/continuation-dispatch-retry.js +109 -0
  409. package/dist/agent/engine/continuation-dispatch-retry.js.map +1 -0
  410. package/dist/agent/engine/tool-call-journal-seed.d.ts +46 -0
  411. package/dist/agent/engine/tool-call-journal-seed.d.ts.map +1 -0
  412. package/dist/agent/engine/tool-call-journal-seed.js +60 -0
  413. package/dist/agent/engine/tool-call-journal-seed.js.map +1 -0
  414. package/dist/agent/production-agent.d.ts +7 -0
  415. package/dist/agent/production-agent.d.ts.map +1 -1
  416. package/dist/agent/production-agent.js +102 -222
  417. package/dist/agent/production-agent.js.map +1 -1
  418. package/dist/cli/doctor.d.ts.map +1 -1
  419. package/dist/cli/doctor.js +7 -3
  420. package/dist/cli/doctor.js.map +1 -1
  421. package/dist/cli/plan-local.d.ts.map +1 -1
  422. package/dist/cli/plan-local.js +8 -2
  423. package/dist/cli/plan-local.js.map +1 -1
  424. package/dist/cli/skills-content/assets-skill.d.ts +2 -0
  425. package/dist/cli/skills-content/assets-skill.d.ts.map +1 -0
  426. package/dist/cli/skills-content/assets-skill.js +84 -0
  427. package/dist/cli/skills-content/assets-skill.js.map +1 -0
  428. package/dist/cli/skills-content/canvas.d.ts +4 -0
  429. package/dist/cli/skills-content/canvas.d.ts.map +1 -0
  430. package/dist/cli/skills-content/canvas.js +152 -0
  431. package/dist/cli/skills-content/canvas.js.map +1 -0
  432. package/dist/cli/skills-content/connection.d.ts +2 -0
  433. package/dist/cli/skills-content/connection.d.ts.map +1 -0
  434. package/dist/cli/skills-content/connection.js +53 -0
  435. package/dist/cli/skills-content/connection.js.map +1 -0
  436. package/dist/cli/skills-content/content-skill.d.ts +2 -0
  437. package/dist/cli/skills-content/content-skill.d.ts.map +1 -0
  438. package/dist/cli/skills-content/content-skill.js +110 -0
  439. package/dist/cli/skills-content/content-skill.js.map +1 -0
  440. package/dist/cli/skills-content/design-exploration-skill.d.ts +2 -0
  441. package/dist/cli/skills-content/design-exploration-skill.d.ts.map +1 -0
  442. package/dist/cli/skills-content/design-exploration-skill.js +119 -0
  443. package/dist/cli/skills-content/design-exploration-skill.js.map +1 -0
  444. package/dist/cli/skills-content/design-visual-edit-skill.d.ts +2 -0
  445. package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -0
  446. package/dist/cli/skills-content/design-visual-edit-skill.js +229 -0
  447. package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -0
  448. package/dist/cli/skills-content/document-quality.d.ts +4 -0
  449. package/dist/cli/skills-content/document-quality.d.ts.map +1 -0
  450. package/dist/cli/skills-content/document-quality.js +195 -0
  451. package/dist/cli/skills-content/document-quality.js.map +1 -0
  452. package/dist/cli/skills-content/exemplar.d.ts +4 -0
  453. package/dist/cli/skills-content/exemplar.d.ts.map +1 -0
  454. package/dist/cli/skills-content/exemplar.js +68 -0
  455. package/dist/cli/skills-content/exemplar.js.map +1 -0
  456. package/dist/cli/skills-content/help.d.ts +2 -0
  457. package/dist/cli/skills-content/help.d.ts.map +1 -0
  458. package/dist/cli/skills-content/help.js +78 -0
  459. package/dist/cli/skills-content/help.js.map +1 -0
  460. package/dist/cli/skills-content/index.d.ts +23 -0
  461. package/dist/cli/skills-content/index.d.ts.map +1 -0
  462. package/dist/cli/skills-content/index.js +23 -0
  463. package/dist/cli/skills-content/index.js.map +1 -0
  464. package/dist/cli/skills-content/local-files.d.ts +2 -0
  465. package/dist/cli/skills-content/local-files.d.ts.map +1 -0
  466. package/dist/cli/skills-content/local-files.js +96 -0
  467. package/dist/cli/skills-content/local-files.js.map +1 -0
  468. package/dist/cli/skills-content/plan-setup-auth.d.ts +9 -0
  469. package/dist/cli/skills-content/plan-setup-auth.d.ts.map +1 -0
  470. package/dist/cli/skills-content/plan-setup-auth.js +81 -0
  471. package/dist/cli/skills-content/plan-setup-auth.js.map +1 -0
  472. package/dist/cli/skills-content/visual-plan-skill.d.ts +2 -0
  473. package/dist/cli/skills-content/visual-plan-skill.d.ts.map +1 -0
  474. package/dist/cli/skills-content/visual-plan-skill.js +471 -0
  475. package/dist/cli/skills-content/visual-plan-skill.js.map +1 -0
  476. package/dist/cli/skills-content/visual-recap-skill.d.ts +2 -0
  477. package/dist/cli/skills-content/visual-recap-skill.d.ts.map +1 -0
  478. package/dist/cli/skills-content/visual-recap-skill.js +548 -0
  479. package/dist/cli/skills-content/visual-recap-skill.js.map +1 -0
  480. package/dist/cli/skills-content/visualize-repo-skill.d.ts +2 -0
  481. package/dist/cli/skills-content/visualize-repo-skill.d.ts.map +1 -0
  482. package/dist/cli/skills-content/visualize-repo-skill.js +94 -0
  483. package/dist/cli/skills-content/visualize-repo-skill.js.map +1 -0
  484. package/dist/cli/skills-content/wireframe.d.ts +4 -0
  485. package/dist/cli/skills-content/wireframe.d.ts.map +1 -0
  486. package/dist/cli/skills-content/wireframe.js +347 -0
  487. package/dist/cli/skills-content/wireframe.js.map +1 -0
  488. package/dist/cli/skills.d.ts +2 -10
  489. package/dist/cli/skills.d.ts.map +1 -1
  490. package/dist/cli/skills.js +2 -2710
  491. package/dist/cli/skills.js.map +1 -1
  492. package/dist/client/AgentPanel.d.ts.map +1 -1
  493. package/dist/client/AgentPanel.js +4 -2
  494. package/dist/client/AgentPanel.js.map +1 -1
  495. package/dist/client/CommandMenu.d.ts.map +1 -1
  496. package/dist/client/CommandMenu.js +15 -3
  497. package/dist/client/CommandMenu.js.map +1 -1
  498. package/dist/client/FeedbackButton.js +2 -2
  499. package/dist/client/FeedbackButton.js.map +1 -1
  500. package/dist/client/app-providers.d.ts +13 -5
  501. package/dist/client/app-providers.d.ts.map +1 -1
  502. package/dist/client/app-providers.js +9 -6
  503. package/dist/client/app-providers.js.map +1 -1
  504. package/dist/client/chat/tool-call-display.d.ts +4 -0
  505. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  506. package/dist/client/chat/tool-call-display.js +3 -3
  507. package/dist/client/chat/tool-call-display.js.map +1 -1
  508. package/dist/client/composer/PastedTextChip.js +1 -1
  509. package/dist/client/composer/PastedTextChip.js.map +1 -1
  510. package/dist/client/composer/RealtimeVoiceMode.d.ts +3 -1
  511. package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
  512. package/dist/client/composer/RealtimeVoiceMode.js +35 -14
  513. package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
  514. package/dist/client/composer/TiptapComposer.js +1 -1
  515. package/dist/client/composer/TiptapComposer.js.map +1 -1
  516. package/dist/client/composer/VoiceButton.d.ts +2 -0
  517. package/dist/client/composer/VoiceButton.d.ts.map +1 -1
  518. package/dist/client/composer/VoiceButton.js +9 -3
  519. package/dist/client/composer/VoiceButton.js.map +1 -1
  520. package/dist/client/composer/useRealtimeVoiceMode.d.ts +5 -0
  521. package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
  522. package/dist/client/composer/useRealtimeVoiceMode.js +91 -12
  523. package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
  524. package/dist/client/context-xray/ContextXRayPanel.d.ts.map +1 -1
  525. package/dist/client/context-xray/ContextXRayPanel.js +4 -1
  526. package/dist/client/context-xray/ContextXRayPanel.js.map +1 -1
  527. package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
  528. package/dist/client/extensions/ExtensionEditor.js +15 -5
  529. package/dist/client/extensions/ExtensionEditor.js.map +1 -1
  530. package/dist/client/extensions/ExtensionQueryErrorState.d.ts +8 -0
  531. package/dist/client/extensions/ExtensionQueryErrorState.d.ts.map +1 -0
  532. package/dist/client/extensions/ExtensionQueryErrorState.js +11 -0
  533. package/dist/client/extensions/ExtensionQueryErrorState.js.map +1 -0
  534. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  535. package/dist/client/extensions/ExtensionSlot.js +17 -7
  536. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  537. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  538. package/dist/client/extensions/ExtensionViewer.js +17 -7
  539. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  540. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
  541. package/dist/client/extensions/ExtensionsListPage.js +5 -3
  542. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  543. package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
  544. package/dist/client/extensions/ExtensionsSidebarSection.js +21 -8
  545. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  546. package/dist/client/index.d.ts +0 -2
  547. package/dist/client/index.d.ts.map +1 -1
  548. package/dist/client/index.js +0 -5
  549. package/dist/client/index.js.map +1 -1
  550. package/dist/client/progress/RunsTray.d.ts.map +1 -1
  551. package/dist/client/progress/RunsTray.js +7 -3
  552. package/dist/client/progress/RunsTray.js.map +1 -1
  553. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  554. package/dist/client/settings/SettingsTabsPage.js +4 -0
  555. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  556. package/dist/client/settings/useBuilderStatus.d.ts +2 -0
  557. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  558. package/dist/client/settings/useBuilderStatus.js +4 -0
  559. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  560. package/dist/client/tool-cells/EditCell.d.ts.map +1 -1
  561. package/dist/client/tool-cells/EditCell.js +2 -1
  562. package/dist/client/tool-cells/EditCell.js.map +1 -1
  563. package/dist/client/tool-cells/FilesChangedSummary.d.ts.map +1 -1
  564. package/dist/client/tool-cells/FilesChangedSummary.js +2 -1
  565. package/dist/client/tool-cells/FilesChangedSummary.js.map +1 -1
  566. package/dist/client/tool-cells/WriteCell.d.ts.map +1 -1
  567. package/dist/client/tool-cells/WriteCell.js +2 -1
  568. package/dist/client/tool-cells/WriteCell.js.map +1 -1
  569. package/dist/client/visual-style-controls.js +1 -1
  570. package/dist/client/visual-style-controls.js.map +1 -1
  571. package/dist/collab/routes.d.ts +1 -1
  572. package/dist/deploy/build.d.ts.map +1 -1
  573. package/dist/deploy/build.js +36 -14
  574. package/dist/deploy/build.js.map +1 -1
  575. package/dist/integrations/google-docs-poller.d.ts +7 -0
  576. package/dist/integrations/google-docs-poller.d.ts.map +1 -1
  577. package/dist/integrations/google-docs-poller.js +13 -3
  578. package/dist/integrations/google-docs-poller.js.map +1 -1
  579. package/dist/integrations/plugin.d.ts.map +1 -1
  580. package/dist/integrations/plugin.js +10 -0
  581. package/dist/integrations/plugin.js.map +1 -1
  582. package/dist/integrations/webhook-handler.d.ts +11 -0
  583. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  584. package/dist/integrations/webhook-handler.js +16 -4
  585. package/dist/integrations/webhook-handler.js.map +1 -1
  586. package/dist/jobs/scheduler.d.ts +12 -0
  587. package/dist/jobs/scheduler.d.ts.map +1 -1
  588. package/dist/jobs/scheduler.js +13 -3
  589. package/dist/jobs/scheduler.js.map +1 -1
  590. package/dist/localization/default-messages.d.ts +7 -0
  591. package/dist/localization/default-messages.d.ts.map +1 -1
  592. package/dist/localization/default-messages.js +8 -1
  593. package/dist/localization/default-messages.js.map +1 -1
  594. package/dist/mcp/oauth-token.d.ts +1 -1
  595. package/dist/mcp/oauth-token.d.ts.map +1 -1
  596. package/dist/mcp/oauth-token.js +6 -1
  597. package/dist/mcp/oauth-token.js.map +1 -1
  598. package/dist/notifications/routes.d.ts +2 -2
  599. package/dist/observability/routes.d.ts.map +1 -1
  600. package/dist/observability/routes.js +32 -0
  601. package/dist/observability/routes.js.map +1 -1
  602. package/dist/observability/sentiment.d.ts +42 -0
  603. package/dist/observability/sentiment.d.ts.map +1 -0
  604. package/dist/observability/sentiment.js +196 -0
  605. package/dist/observability/sentiment.js.map +1 -0
  606. package/dist/observability/store.d.ts +5 -0
  607. package/dist/observability/store.d.ts.map +1 -1
  608. package/dist/observability/store.js +17 -0
  609. package/dist/observability/store.js.map +1 -1
  610. package/dist/observability/traces.d.ts +2 -0
  611. package/dist/observability/traces.d.ts.map +1 -1
  612. package/dist/observability/traces.js +42 -57
  613. package/dist/observability/traces.js.map +1 -1
  614. package/dist/observability/tracking-identity.d.ts +3 -0
  615. package/dist/observability/tracking-identity.d.ts.map +1 -0
  616. package/dist/observability/tracking-identity.js +51 -0
  617. package/dist/observability/tracking-identity.js.map +1 -0
  618. package/dist/observability/types.d.ts +10 -0
  619. package/dist/observability/types.d.ts.map +1 -1
  620. package/dist/observability/types.js +3 -0
  621. package/dist/observability/types.js.map +1 -1
  622. package/dist/progress/routes.d.ts +1 -1
  623. package/dist/provider-api/corpus-jobs.d.ts +2 -2
  624. package/dist/resources/handlers.d.ts +1 -1
  625. package/dist/secrets/storage.d.ts +6 -0
  626. package/dist/secrets/storage.d.ts.map +1 -1
  627. package/dist/secrets/storage.js +61 -3
  628. package/dist/secrets/storage.js.map +1 -1
  629. package/dist/server/agent-chat/action-filters-a2a.d.ts +50 -0
  630. package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -0
  631. package/dist/server/agent-chat/action-filters-a2a.js +127 -0
  632. package/dist/server/agent-chat/action-filters-a2a.js.map +1 -0
  633. package/dist/server/agent-chat/browser-team-tools.d.ts +21 -0
  634. package/dist/server/agent-chat/browser-team-tools.d.ts.map +1 -0
  635. package/dist/server/agent-chat/browser-team-tools.js +417 -0
  636. package/dist/server/agent-chat/browser-team-tools.js.map +1 -0
  637. package/dist/server/agent-chat/context-tools.d.ts +33 -0
  638. package/dist/server/agent-chat/context-tools.d.ts.map +1 -0
  639. package/dist/server/agent-chat/context-tools.js +520 -0
  640. package/dist/server/agent-chat/context-tools.js.map +1 -0
  641. package/dist/server/agent-chat/framework-prompts.d.ts +65 -0
  642. package/dist/server/agent-chat/framework-prompts.d.ts.map +1 -0
  643. package/dist/server/agent-chat/framework-prompts.js +403 -0
  644. package/dist/server/agent-chat/framework-prompts.js.map +1 -0
  645. package/dist/server/agent-chat/lazy-fs.d.ts +2 -0
  646. package/dist/server/agent-chat/lazy-fs.d.ts.map +1 -0
  647. package/dist/server/agent-chat/lazy-fs.js +11 -0
  648. package/dist/server/agent-chat/lazy-fs.js.map +1 -0
  649. package/dist/server/agent-chat/mcp-glue.d.ts +9 -0
  650. package/dist/server/agent-chat/mcp-glue.d.ts.map +1 -0
  651. package/dist/server/agent-chat/mcp-glue.js +63 -0
  652. package/dist/server/agent-chat/mcp-glue.js.map +1 -0
  653. package/dist/server/agent-chat/plugin-options.d.ts +322 -0
  654. package/dist/server/agent-chat/plugin-options.d.ts.map +1 -0
  655. package/dist/server/agent-chat/plugin-options.js +2 -0
  656. package/dist/server/agent-chat/plugin-options.js.map +1 -0
  657. package/dist/server/agent-chat/process-run-failure.d.ts +12 -0
  658. package/dist/server/agent-chat/process-run-failure.d.ts.map +1 -0
  659. package/dist/server/agent-chat/process-run-failure.js +24 -0
  660. package/dist/server/agent-chat/process-run-failure.js.map +1 -0
  661. package/dist/server/agent-chat/prompt-resources.d.ts +28 -0
  662. package/dist/server/agent-chat/prompt-resources.d.ts.map +1 -0
  663. package/dist/server/agent-chat/prompt-resources.js +514 -0
  664. package/dist/server/agent-chat/prompt-resources.js.map +1 -0
  665. package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +5 -0
  666. package/dist/server/agent-chat/recurring-jobs-runtime.d.ts.map +1 -0
  667. package/dist/server/agent-chat/recurring-jobs-runtime.js +53 -0
  668. package/dist/server/agent-chat/recurring-jobs-runtime.js.map +1 -0
  669. package/dist/server/agent-chat/request-surface.d.ts +8 -0
  670. package/dist/server/agent-chat/request-surface.d.ts.map +1 -0
  671. package/dist/server/agent-chat/request-surface.js +56 -0
  672. package/dist/server/agent-chat/request-surface.js.map +1 -0
  673. package/dist/server/agent-chat/run-code-tools.d.ts +17 -0
  674. package/dist/server/agent-chat/run-code-tools.d.ts.map +1 -0
  675. package/dist/server/agent-chat/run-code-tools.js +55 -0
  676. package/dist/server/agent-chat/run-code-tools.js.map +1 -0
  677. package/dist/server/agent-chat/script-entries.d.ts +47 -0
  678. package/dist/server/agent-chat/script-entries.d.ts.map +1 -0
  679. package/dist/server/agent-chat/script-entries.js +633 -0
  680. package/dist/server/agent-chat/script-entries.js.map +1 -0
  681. package/dist/server/agent-chat/shared-thread.d.ts +33 -0
  682. package/dist/server/agent-chat/shared-thread.d.ts.map +1 -0
  683. package/dist/server/agent-chat/shared-thread.js +242 -0
  684. package/dist/server/agent-chat/shared-thread.js.map +1 -0
  685. package/dist/server/agent-chat/skill-frontmatter.d.ts +7 -0
  686. package/dist/server/agent-chat/skill-frontmatter.d.ts.map +1 -0
  687. package/dist/server/agent-chat/skill-frontmatter.js +26 -0
  688. package/dist/server/agent-chat/skill-frontmatter.js.map +1 -0
  689. package/dist/server/agent-chat-plugin.d.ts +45 -486
  690. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  691. package/dist/server/agent-chat-plugin.js +173 -3005
  692. package/dist/server/agent-chat-plugin.js.map +1 -1
  693. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  694. package/dist/server/agent-teams.d.ts +10 -0
  695. package/dist/server/agent-teams.d.ts.map +1 -1
  696. package/dist/server/agent-teams.js +13 -3
  697. package/dist/server/agent-teams.js.map +1 -1
  698. package/dist/server/auth.d.ts.map +1 -1
  699. package/dist/server/auth.js +50 -52
  700. package/dist/server/auth.js.map +1 -1
  701. package/dist/server/credential-provider.d.ts.map +1 -1
  702. package/dist/server/credential-provider.js +22 -21
  703. package/dist/server/credential-provider.js.map +1 -1
  704. package/dist/server/edge.d.ts +1 -0
  705. package/dist/server/edge.d.ts.map +1 -1
  706. package/dist/server/edge.js +1 -0
  707. package/dist/server/edge.js.map +1 -1
  708. package/dist/server/onboarding-html.d.ts.map +1 -1
  709. package/dist/server/onboarding-html.js +1 -16
  710. package/dist/server/onboarding-html.js.map +1 -1
  711. package/dist/server/realtime-voice.d.ts +3 -0
  712. package/dist/server/realtime-voice.d.ts.map +1 -1
  713. package/dist/server/realtime-voice.js +29 -5
  714. package/dist/server/realtime-voice.js.map +1 -1
  715. package/dist/server/request-origin.d.ts.map +1 -1
  716. package/dist/server/request-origin.js +6 -3
  717. package/dist/server/request-origin.js.map +1 -1
  718. package/dist/server/ssr-handler.d.ts.map +1 -1
  719. package/dist/server/ssr-handler.js +47 -2
  720. package/dist/server/ssr-handler.js.map +1 -1
  721. package/dist/sharing/access.d.ts +63 -3
  722. package/dist/sharing/access.d.ts.map +1 -1
  723. package/dist/sharing/access.js +53 -15
  724. package/dist/sharing/access.js.map +1 -1
  725. package/dist/sharing/registry.d.ts +7 -0
  726. package/dist/sharing/registry.d.ts.map +1 -1
  727. package/dist/sharing/registry.js.map +1 -1
  728. package/dist/styles/agent-native.css +15 -14
  729. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +1 -1
  730. package/dist/templates/default/app/i18n/ar-SA.ts +6 -0
  731. package/dist/templates/default/app/i18n/de-DE.ts +6 -0
  732. package/dist/templates/default/app/i18n/en-US.ts +6 -0
  733. package/dist/templates/default/app/i18n/es-ES.ts +6 -0
  734. package/dist/templates/default/app/i18n/fr-FR.ts +6 -0
  735. package/dist/templates/default/app/i18n/hi-IN.ts +6 -0
  736. package/dist/templates/default/app/i18n/ja-JP.ts +6 -0
  737. package/dist/templates/default/app/i18n/ko-KR.ts +6 -0
  738. package/dist/templates/default/app/i18n/pt-BR.ts +6 -0
  739. package/dist/templates/default/app/i18n/zh-CN.ts +6 -0
  740. package/dist/templates/default/app/i18n/zh-TW.ts +6 -0
  741. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +27 -29
  742. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +2 -1
  743. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -1
  744. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +32 -0
  745. package/dist/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +25 -0
  746. package/dist/templates/workspace-core/src/server/index.ts +4 -2
  747. package/dist/testing.d.ts +16 -0
  748. package/dist/testing.d.ts.map +1 -0
  749. package/dist/testing.js +16 -0
  750. package/dist/testing.js.map +1 -0
  751. package/dist/triggers/dispatcher.d.ts +7 -0
  752. package/dist/triggers/dispatcher.d.ts.map +1 -1
  753. package/dist/triggers/dispatcher.js +13 -3
  754. package/dist/triggers/dispatcher.js.map +1 -1
  755. package/dist/vite/client.d.ts +16 -1
  756. package/dist/vite/client.d.ts.map +1 -1
  757. package/dist/vite/client.js +105 -2
  758. package/dist/vite/client.js.map +1 -1
  759. package/docs/content/authentication.mdx +3 -3
  760. package/docs/content/doctor.mdx +170 -0
  761. package/docs/content/external-agents.mdx +8 -7
  762. package/docs/content/locales/ar-SA/authentication.mdx +2 -2
  763. package/docs/content/locales/ar-SA/external-agents.mdx +8 -7
  764. package/docs/content/locales/ar-SA/mcp-protocol.mdx +1 -1
  765. package/docs/content/locales/ar-SA/security.mdx +2 -0
  766. package/docs/content/locales/de-DE/authentication.mdx +1 -1
  767. package/docs/content/locales/de-DE/external-agents.mdx +8 -7
  768. package/docs/content/locales/de-DE/mcp-protocol.mdx +1 -1
  769. package/docs/content/locales/de-DE/security.mdx +2 -0
  770. package/docs/content/locales/es-ES/authentication.mdx +2 -2
  771. package/docs/content/locales/es-ES/external-agents.mdx +8 -7
  772. package/docs/content/locales/es-ES/mcp-protocol.mdx +1 -1
  773. package/docs/content/locales/es-ES/security.mdx +2 -0
  774. package/docs/content/locales/fr-FR/authentication.mdx +1 -1
  775. package/docs/content/locales/fr-FR/external-agents.mdx +8 -7
  776. package/docs/content/locales/fr-FR/mcp-protocol.mdx +1 -1
  777. package/docs/content/locales/fr-FR/security.mdx +2 -0
  778. package/docs/content/locales/hi-IN/authentication.mdx +2 -2
  779. package/docs/content/locales/hi-IN/external-agents.mdx +8 -7
  780. package/docs/content/locales/hi-IN/mcp-protocol.mdx +1 -1
  781. package/docs/content/locales/hi-IN/security.mdx +2 -0
  782. package/docs/content/locales/ja-JP/authentication.mdx +2 -2
  783. package/docs/content/locales/ja-JP/external-agents.mdx +8 -7
  784. package/docs/content/locales/ja-JP/mcp-protocol.mdx +1 -1
  785. package/docs/content/locales/ja-JP/security.mdx +2 -0
  786. package/docs/content/locales/ko-KR/authentication.mdx +2 -2
  787. package/docs/content/locales/ko-KR/external-agents.mdx +8 -7
  788. package/docs/content/locales/ko-KR/mcp-protocol.mdx +1 -1
  789. package/docs/content/locales/ko-KR/security.mdx +2 -0
  790. package/docs/content/locales/pt-BR/authentication.mdx +2 -2
  791. package/docs/content/locales/pt-BR/external-agents.mdx +8 -7
  792. package/docs/content/locales/pt-BR/mcp-protocol.mdx +1 -1
  793. package/docs/content/locales/pt-BR/security.mdx +2 -0
  794. package/docs/content/locales/zh-CN/authentication.mdx +2 -2
  795. package/docs/content/locales/zh-CN/external-agents.mdx +8 -7
  796. package/docs/content/locales/zh-CN/mcp-protocol.mdx +1 -1
  797. package/docs/content/locales/zh-CN/security.mdx +2 -0
  798. package/docs/content/locales/zh-TW/authentication.mdx +2 -2
  799. package/docs/content/locales/zh-TW/external-agents.mdx +8 -7
  800. package/docs/content/locales/zh-TW/mcp-protocol.mdx +1 -1
  801. package/docs/content/locales/zh-TW/security.mdx +2 -0
  802. package/docs/content/mcp-protocol.mdx +1 -1
  803. package/docs/content/security.mdx +2 -0
  804. package/package.json +6 -2
  805. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +1 -1
  806. package/src/templates/default/app/i18n/ar-SA.ts +6 -0
  807. package/src/templates/default/app/i18n/de-DE.ts +6 -0
  808. package/src/templates/default/app/i18n/en-US.ts +6 -0
  809. package/src/templates/default/app/i18n/es-ES.ts +6 -0
  810. package/src/templates/default/app/i18n/fr-FR.ts +6 -0
  811. package/src/templates/default/app/i18n/hi-IN.ts +6 -0
  812. package/src/templates/default/app/i18n/ja-JP.ts +6 -0
  813. package/src/templates/default/app/i18n/ko-KR.ts +6 -0
  814. package/src/templates/default/app/i18n/pt-BR.ts +6 -0
  815. package/src/templates/default/app/i18n/zh-CN.ts +6 -0
  816. package/src/templates/default/app/i18n/zh-TW.ts +6 -0
  817. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +27 -29
  818. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +2 -1
  819. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +1 -1
  820. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +32 -0
  821. package/src/templates/workspace-core/.agents/skills/writing-agent-instructions/SKILL.md +25 -0
  822. package/src/templates/workspace-core/src/server/index.ts +4 -2
  823. package/corpus/core/src/client/ProductionAgentPanel.tsx +0 -9
  824. package/corpus/core/src/client/auth-redirect-url.ts +0 -23
  825. package/corpus/core/src/client/useProductionAgent.ts +0 -253
  826. package/corpus/core/src/shared/auth-redirect-url.ts +0 -1
  827. package/corpus/templates/analytics/app/pages/Index.tsx +0 -16
  828. package/corpus/templates/analytics/seeds/dashboards/agent-observability-llm.json +0 -173
  829. package/dist/client/ProductionAgentPanel.d.ts +0 -6
  830. package/dist/client/ProductionAgentPanel.d.ts.map +0 -1
  831. package/dist/client/ProductionAgentPanel.js +0 -6
  832. package/dist/client/ProductionAgentPanel.js.map +0 -1
  833. package/dist/client/auth-redirect-url.d.ts +0 -2
  834. package/dist/client/auth-redirect-url.d.ts.map +0 -1
  835. package/dist/client/auth-redirect-url.js +0 -19
  836. package/dist/client/auth-redirect-url.js.map +0 -1
  837. package/dist/client/useProductionAgent.d.ts +0 -24
  838. package/dist/client/useProductionAgent.d.ts.map +0 -1
  839. package/dist/client/useProductionAgent.js +0 -179
  840. package/dist/client/useProductionAgent.js.map +0 -1
  841. package/dist/shared/auth-redirect-url.d.ts +0 -2
  842. package/dist/shared/auth-redirect-url.d.ts.map +0 -1
  843. package/dist/shared/auth-redirect-url.js +0 -2
  844. package/dist/shared/auth-redirect-url.js.map +0 -1
@@ -234,6 +234,9 @@ import {
234
234
  } from "../previewDocumentSaveRegistry";
235
235
  import { VisualEditor } from "../VisualEditor";
236
236
  import { DatabaseFormView } from "./FormView";
237
+ import { DatabaseGalleryView } from "./GalleryView";
238
+ import { DatabaseListView } from "./ListView";
239
+ import { DatabaseTimelineView } from "./TimelineView";
237
240
 
238
241
  export interface DatabaseViewProps {
239
242
  databaseId: string;
@@ -288,7 +291,7 @@ export type PersonalDatabaseViewOverrides =
288
291
 
289
292
  type DatabaseMessageKey = keyof (typeof messagesByLocale)["en-US"]["database"];
290
293
 
291
- function dbText(
294
+ export function dbText(
292
295
  key: DatabaseMessageKey,
293
296
  values?: Record<string, string | number>,
294
297
  ): string {
@@ -307,7 +310,7 @@ function dbText(
307
310
  );
308
311
  }
309
312
 
310
- type CreateDatabaseRowHandler = (
313
+ export type CreateDatabaseRowHandler = (
311
314
  title?: string,
312
315
  ) => Promise<ContentDatabaseItem | null>;
313
316
  type DatabaseDragPreviewState =
@@ -438,7 +441,7 @@ export function databaseItemPageIconText(
438
441
  return icon ? icon : null;
439
442
  }
440
443
 
441
- function DatabaseItemPageIcon({
444
+ export function DatabaseItemPageIcon({
442
445
  document,
443
446
  className,
444
447
  fallbackClassName,
@@ -9467,7 +9470,7 @@ export function databaseViewHasNoMatchingPages(
9467
9470
  return visibleCount === 0 && (hasSearch || activeFilterCount > 0);
9468
9471
  }
9469
9472
 
9470
- function DatabaseNoMatchingPages({
9473
+ export function DatabaseNoMatchingPages({
9471
9474
  label = "No pages match this view",
9472
9475
  className,
9473
9476
  onClear,
@@ -9522,1156 +9525,39 @@ function DatabaseConstraintChip({
9522
9525
  );
9523
9526
  }
9524
9527
 
9525
- function DatabaseListView({
9526
- properties,
9527
- groupableProperties,
9528
- items,
9529
- databaseDocumentId,
9530
- canEdit,
9531
- isLoading,
9532
- isCreating,
9533
- activeFilters,
9534
- hasSearch,
9535
- rowsAreManuallyOrdered,
9536
- groupByPropertyId,
9537
- collapsedGroupIds,
9538
- hideEmptyGroups,
9539
- onClearResultConstraints,
9540
- onCreateRow,
9541
- onCreateGroupedRow,
9542
- onGroupCollapsedChange,
9543
- onPreview,
9544
- onDeletedPreviewItem,
9545
- onOpenPage,
9546
- }: {
9547
- properties: DocumentProperty[];
9548
- groupableProperties: DocumentProperty[];
9549
- items: ContentDatabaseItem[];
9550
- databaseDocumentId: string;
9551
- canEdit: boolean;
9552
- isLoading: boolean;
9553
- isCreating: boolean;
9554
- activeFilters: DatabaseFilter[];
9555
- hasSearch: boolean;
9556
- rowsAreManuallyOrdered: boolean;
9557
- groupByPropertyId: string | null;
9558
- collapsedGroupIds: string[];
9559
- hideEmptyGroups: boolean;
9560
- onClearResultConstraints: () => void;
9561
- onCreateRow: CreateDatabaseRowHandler;
9562
- onCreateGroupedRow: (
9563
- group: DatabaseBoardGroup,
9564
- title?: string,
9565
- ) => Promise<ContentDatabaseItem | null>;
9566
- onGroupCollapsedChange: (groupId: string, collapsed: boolean) => void;
9567
- onPreview: (item: ContentDatabaseItem) => void;
9568
- onDeletedPreviewItem: (item: ContentDatabaseItem) => boolean;
9569
- onOpenPage: (item: ContentDatabaseItem) => void;
9570
- }) {
9571
- const groups = databaseVisibleGroups(
9572
- databaseViewItemGroups(items, groupableProperties, groupByPropertyId),
9573
- hideEmptyGroups,
9574
- );
9575
- const grouped = !!databaseViewGroupingProperty(
9576
- { type: "list", groupByPropertyId },
9577
- groupableProperties,
9578
- );
9579
-
9580
- return (
9581
- <div className="border-b border-border">
9582
- <div className="flex min-h-9 items-center gap-2 border-t border-border px-1 text-xs text-muted-foreground">
9583
- <IconList className="size-4 shrink-0" />
9584
- <span>List</span>
9585
- </div>
9586
- {isLoading ? (
9587
- <div className="flex h-16 items-center gap-2 px-2 text-sm text-muted-foreground">
9588
- <Spinner className="size-4" />
9589
- {dbText("loadingList")}
9590
- </div>
9591
- ) : (
9592
- <div className="grid">
9593
- {databaseViewHasNoMatchingPages(
9594
- items.length,
9595
- hasSearch,
9596
- activeFilters.length,
9597
- ) ? (
9598
- <DatabaseNoMatchingPages onClear={onClearResultConstraints} />
9599
- ) : null}
9600
- {grouped
9601
- ? groups.map((group) => (
9602
- <DatabaseGroupedListSection
9603
- key={group.id}
9604
- group={group}
9605
- properties={properties}
9606
- databaseDocumentId={databaseDocumentId}
9607
- canEdit={canEdit}
9608
- isCreating={isCreating}
9609
- collapsed={databaseGroupIsCollapsed(
9610
- collapsedGroupIds,
9611
- group.id,
9612
- )}
9613
- onCreateRow={onCreateGroupedRow}
9614
- onCollapsedChange={(collapsed) =>
9615
- onGroupCollapsedChange(group.id, collapsed)
9616
- }
9617
- onPreview={onPreview}
9618
- onDeletedPreviewItem={onDeletedPreviewItem}
9619
- onOpenPage={onOpenPage}
9620
- />
9621
- ))
9622
- : items.map((item, index) => (
9623
- <DatabaseListRow
9624
- key={item.id}
9625
- item={item}
9626
- properties={properties}
9627
- databaseDocumentId={databaseDocumentId}
9628
- canEdit={canEdit}
9629
- rowIndex={index}
9630
- canReorder={rowsAreManuallyOrdered}
9631
- canMoveUp={rowsAreManuallyOrdered && index > 0}
9632
- canMoveDown={
9633
- rowsAreManuallyOrdered && index < items.length - 1
9634
- }
9635
- onPreviewItem={onPreview}
9636
- onDeletedPreviewItem={onDeletedPreviewItem}
9637
- onPreview={() => onPreview(item)}
9638
- onOpenPage={() => onOpenPage(item)}
9639
- />
9640
- ))}
9641
- {canEdit && !grouped ? (
9642
- <NewListRow
9643
- disabled={isCreating}
9644
- isPending={isCreating}
9645
- onCreate={onCreateRow}
9646
- />
9647
- ) : null}
9648
- </div>
9649
- )}
9650
- </div>
9651
- );
9652
- }
9653
-
9654
- function DatabaseGroupedListSection({
9655
- group,
9656
- properties,
9657
- databaseDocumentId,
9658
- canEdit,
9659
- isCreating,
9660
- collapsed,
9661
- onCreateRow,
9662
- onCollapsedChange,
9663
- onPreview,
9664
- onDeletedPreviewItem,
9665
- onOpenPage,
9666
- }: {
9667
- group: DatabaseBoardGroup;
9668
- properties: DocumentProperty[];
9669
- databaseDocumentId: string;
9670
- canEdit: boolean;
9671
- isCreating: boolean;
9672
- collapsed: boolean;
9673
- onCreateRow: (
9674
- group: DatabaseBoardGroup,
9675
- title?: string,
9676
- ) => Promise<ContentDatabaseItem | null>;
9677
- onCollapsedChange: (collapsed: boolean) => void;
9678
- onPreview: (item: ContentDatabaseItem) => void;
9679
- onDeletedPreviewItem: (item: ContentDatabaseItem) => boolean;
9680
- onOpenPage: (item: ContentDatabaseItem) => void;
9681
- }) {
9682
- return (
9683
- <section>
9684
- <DatabaseGroupHeader
9685
- group={group}
9686
- collapsed={collapsed}
9687
- onCollapsedChange={onCollapsedChange}
9688
- />
9689
- {!collapsed ? (
9690
- <>
9691
- {group.items.map((item, index) => (
9692
- <DatabaseListRow
9693
- key={`${group.id}-${item.id}`}
9694
- item={item}
9695
- properties={properties}
9696
- databaseDocumentId={databaseDocumentId}
9697
- canEdit={canEdit}
9698
- rowIndex={index}
9699
- canReorder={false}
9700
- canMoveUp={false}
9701
- canMoveDown={false}
9702
- onPreviewItem={onPreview}
9703
- onDeletedPreviewItem={onDeletedPreviewItem}
9704
- onPreview={() => onPreview(item)}
9705
- onOpenPage={() => onOpenPage(item)}
9706
- />
9707
- ))}
9708
- {canEdit ? (
9709
- <NewListRow
9710
- disabled={isCreating}
9711
- isPending={isCreating}
9712
- onCreate={(title) => onCreateRow(group, title)}
9713
- />
9714
- ) : null}
9715
- </>
9716
- ) : null}
9717
- </section>
9718
- );
9719
- }
9720
-
9721
- function DatabaseGroupHeader({
9722
- group,
9723
- collapsed,
9724
- onCollapsedChange,
9725
- }: {
9726
- group: DatabaseBoardGroup;
9727
- collapsed: boolean;
9728
- onCollapsedChange: (collapsed: boolean) => void;
9729
- }) {
9730
- return (
9731
- <button
9732
- type="button"
9733
- className="flex min-h-9 w-full items-center gap-2 border-t border-border bg-muted/30 px-2 text-left text-xs text-muted-foreground hover:bg-muted/45 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
9734
- aria-expanded={!collapsed}
9735
- onClick={() => onCollapsedChange(!collapsed)}
9736
- >
9737
- <IconChevronRight
9738
- className={cn(
9739
- "size-3.5 shrink-0 transition-transform",
9740
- !collapsed && "rotate-90",
9741
- )}
9742
- />
9743
- <span className="min-w-0 truncate font-medium text-foreground">
9744
- {group.label}
9745
- </span>
9746
- <span className="rounded bg-background px-1.5 py-0.5 text-[11px]">
9747
- {group.items.length}
9748
- </span>
9749
- </button>
9750
- );
9751
- }
9752
-
9753
- function DatabaseListRow({
9754
- item,
9755
- properties,
9756
- databaseDocumentId,
9757
- canEdit,
9758
- rowIndex,
9759
- canReorder,
9760
- canMoveUp,
9761
- canMoveDown,
9762
- onPreviewItem,
9763
- onDeletedPreviewItem,
9764
- onPreview,
9765
- onOpenPage,
9766
- }: {
9767
- item: ContentDatabaseItem;
9768
- properties: DocumentProperty[];
9769
- databaseDocumentId: string;
9770
- canEdit: boolean;
9771
- rowIndex: number;
9772
- canReorder: boolean;
9773
- canMoveUp: boolean;
9774
- canMoveDown: boolean;
9775
- onPreviewItem: (item: ContentDatabaseItem) => void;
9776
- onDeletedPreviewItem: (item: ContentDatabaseItem) => boolean;
9777
- onPreview: () => void;
9778
- onOpenPage: () => void;
9779
- }) {
9780
- const visibleProperties = properties.slice(0, 4);
9781
-
9782
- return (
9783
- <div className="group flex min-h-10 items-center gap-2 border-t border-border px-1 py-1 hover:bg-muted/40">
9784
- <button
9785
- type="button"
9786
- className="flex min-w-0 flex-1 items-center gap-2 rounded px-1.5 py-1 text-left hover:bg-accent/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
9787
- onClick={onPreview}
9788
- >
9789
- <DatabaseItemPageIcon
9790
- document={item.document}
9791
- className="size-4 text-sm"
9792
- fallbackClassName="size-4"
9793
- />
9794
- <span className="min-w-0 truncate text-sm font-medium">
9795
- {item.document.title || "Untitled"}
9796
- </span>
9797
- {visibleProperties.length > 0 ? (
9798
- <span className="ml-2 hidden min-w-0 flex-wrap items-center gap-1 md:flex">
9799
- {visibleProperties.map((property) => {
9800
- const itemProperty =
9801
- item.properties.find(
9802
- (candidate) =>
9803
- candidate.definition.id === property.definition.id,
9804
- ) ?? property;
9805
- return (
9806
- <span
9807
- key={property.definition.id}
9808
- className="max-w-36 truncate rounded bg-muted px-1.5 py-0.5 text-xs font-normal text-muted-foreground"
9809
- >
9810
- {displayValue(itemProperty)}
9811
- </span>
9812
- );
9813
- })}
9814
- </span>
9815
- ) : null}
9816
- </button>
9817
- {canEdit ? (
9818
- <RowActionsCell
9819
- item={item}
9820
- databaseDocumentId={databaseDocumentId}
9821
- rowIndex={rowIndex}
9822
- canReorder={canReorder}
9823
- canMoveUp={canMoveUp}
9824
- canMoveDown={canMoveDown}
9825
- onPreviewItem={onPreviewItem}
9826
- onDeletedPreviewItem={onDeletedPreviewItem}
9827
- onOpenPage={onOpenPage}
9828
- />
9829
- ) : null}
9830
- </div>
9831
- );
9832
- }
9833
-
9834
- function NewListRow({
9835
- disabled,
9836
- isPending,
9837
- onCreate,
9838
- }: {
9839
- disabled: boolean;
9840
- isPending: boolean;
9841
- onCreate: CreateDatabaseRowHandler;
9842
- }) {
9843
- const inputRef = useRef<HTMLInputElement>(null);
9844
- const [title, setTitle] = useState("");
9845
-
9846
- async function submitNewRow() {
9847
- if (disabled) return;
9848
- const createdItem = await onCreate(title.trim());
9849
- setTitle("");
9850
- if (!createdItem) inputRef.current?.focus();
9851
- }
9852
-
9853
- return (
9854
- <form
9855
- className="flex h-10 items-center gap-2 border-t border-border px-2 text-sm text-muted-foreground hover:bg-muted/40 focus-within:bg-muted/40 focus-within:text-foreground"
9856
- onSubmit={(event) => {
9857
- event.preventDefault();
9858
- void submitNewRow();
9859
- }}
9860
- >
9861
- {isPending ? (
9862
- <Spinner className="size-4 shrink-0" />
9863
- ) : (
9864
- <IconPlus className="size-4 shrink-0" />
9865
- )}
9866
- <input
9867
- ref={inputRef}
9868
- value={title}
9869
- disabled={disabled}
9870
- aria-label={dbText("newDatabaseListItemTitle")}
9871
- placeholder={dbText("newPage")}
9872
- onChange={(event) => setTitle(event.target.value)}
9873
- onKeyDown={(event) => {
9874
- if (event.key === "Enter") {
9875
- event.preventDefault();
9876
- void submitNewRow();
9877
- }
9878
- if (event.key === "Escape") {
9879
- setTitle("");
9880
- event.currentTarget.blur();
9881
- }
9882
- }}
9883
- className="h-7 min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground focus:placeholder:text-muted-foreground/70"
9884
- />
9885
- </form>
9886
- );
9887
- }
9888
-
9889
- function DatabaseGalleryView({
9890
- properties,
9891
- groupableProperties,
9892
- items,
9893
- databaseDocumentId,
9894
- canEdit,
9895
- isLoading,
9896
- isCreating,
9897
- activeFilters,
9898
- hasSearch,
9899
- rowsAreManuallyOrdered,
9900
- groupByPropertyId,
9901
- collapsedGroupIds,
9902
- hideEmptyGroups,
9903
- onClearResultConstraints,
9904
- onCreateRow,
9905
- onCreateGroupedRow,
9906
- onGroupCollapsedChange,
9907
- onPreview,
9908
- onDeletedPreviewItem,
9909
- onOpenPage,
9910
- }: {
9911
- properties: DocumentProperty[];
9912
- groupableProperties: DocumentProperty[];
9913
- items: ContentDatabaseItem[];
9914
- databaseDocumentId: string;
9915
- canEdit: boolean;
9916
- isLoading: boolean;
9917
- isCreating: boolean;
9918
- activeFilters: DatabaseFilter[];
9919
- hasSearch: boolean;
9920
- rowsAreManuallyOrdered: boolean;
9921
- groupByPropertyId: string | null;
9922
- collapsedGroupIds: string[];
9923
- hideEmptyGroups: boolean;
9924
- onClearResultConstraints: () => void;
9925
- onCreateRow: CreateDatabaseRowHandler;
9926
- onCreateGroupedRow: (
9927
- group: DatabaseBoardGroup,
9928
- title?: string,
9929
- ) => Promise<ContentDatabaseItem | null>;
9930
- onGroupCollapsedChange: (groupId: string, collapsed: boolean) => void;
9931
- onPreview: (item: ContentDatabaseItem) => void;
9932
- onDeletedPreviewItem: (item: ContentDatabaseItem) => boolean;
9933
- onOpenPage: (item: ContentDatabaseItem) => void;
9934
- }) {
9935
- const groups = databaseVisibleGroups(
9936
- databaseViewItemGroups(items, groupableProperties, groupByPropertyId),
9937
- hideEmptyGroups,
9938
- );
9939
- const grouped = !!databaseViewGroupingProperty(
9940
- { type: "gallery", groupByPropertyId },
9941
- groupableProperties,
9942
- );
9943
-
9944
- return (
9945
- <div className="border-b border-border">
9946
- <div className="flex min-h-9 items-center gap-2 border-t border-border px-1 text-xs text-muted-foreground">
9947
- <IconLayoutGrid className="size-4 shrink-0" />
9948
- <span>Gallery</span>
9949
- </div>
9950
- {isLoading ? (
9951
- <div className="flex h-16 items-center gap-2 px-2 text-sm text-muted-foreground">
9952
- <Spinner className="size-4" />
9953
- {dbText("loadingGallery")}
9954
- </div>
9955
- ) : (
9956
- <div className="content-database-gallery-grid grid gap-3 px-1 py-3">
9957
- {databaseViewHasNoMatchingPages(
9958
- items.length,
9959
- hasSearch,
9960
- activeFilters.length,
9961
- ) ? (
9962
- <DatabaseNoMatchingPages
9963
- className="col-span-full"
9964
- onClear={onClearResultConstraints}
9965
- />
9966
- ) : null}
9967
- {grouped
9968
- ? groups.map((group) => (
9969
- <DatabaseGroupedGallerySection
9970
- key={group.id}
9971
- group={group}
9972
- properties={properties}
9973
- databaseDocumentId={databaseDocumentId}
9974
- canEdit={canEdit}
9975
- isCreating={isCreating}
9976
- collapsed={databaseGroupIsCollapsed(
9977
- collapsedGroupIds,
9978
- group.id,
9979
- )}
9980
- onCreateRow={onCreateGroupedRow}
9981
- onCollapsedChange={(collapsed) =>
9982
- onGroupCollapsedChange(group.id, collapsed)
9983
- }
9984
- onPreview={onPreview}
9985
- onDeletedPreviewItem={onDeletedPreviewItem}
9986
- onOpenPage={onOpenPage}
9987
- />
9988
- ))
9989
- : items.map((item, index) => (
9990
- <DatabaseGalleryCard
9991
- key={item.id}
9992
- item={item}
9993
- properties={properties}
9994
- databaseDocumentId={databaseDocumentId}
9995
- canEdit={canEdit}
9996
- rowIndex={index}
9997
- canReorder={rowsAreManuallyOrdered}
9998
- canMoveUp={rowsAreManuallyOrdered && index > 0}
9999
- canMoveDown={
10000
- rowsAreManuallyOrdered && index < items.length - 1
10001
- }
10002
- onPreviewItem={onPreview}
10003
- onDeletedPreviewItem={onDeletedPreviewItem}
10004
- onPreview={() => onPreview(item)}
10005
- onOpenPage={() => onOpenPage(item)}
10006
- />
10007
- ))}
10008
- {canEdit && !grouped ? (
10009
- <NewGalleryCard
10010
- disabled={isCreating}
10011
- isPending={isCreating}
10012
- onCreate={onCreateRow}
10013
- />
10014
- ) : null}
10015
- </div>
10016
- )}
10017
- </div>
10018
- );
10019
- }
10020
-
10021
- function DatabaseGroupedGallerySection({
10022
- group,
10023
- properties,
10024
- databaseDocumentId,
10025
- canEdit,
10026
- isCreating,
10027
- collapsed,
10028
- onCreateRow,
10029
- onCollapsedChange,
10030
- onPreview,
10031
- onDeletedPreviewItem,
10032
- onOpenPage,
10033
- }: {
10034
- group: DatabaseBoardGroup;
10035
- properties: DocumentProperty[];
10036
- databaseDocumentId: string;
10037
- canEdit: boolean;
10038
- isCreating: boolean;
10039
- collapsed: boolean;
10040
- onCreateRow: (
10041
- group: DatabaseBoardGroup,
10042
- title?: string,
10043
- ) => Promise<ContentDatabaseItem | null>;
10044
- onCollapsedChange: (collapsed: boolean) => void;
10045
- onPreview: (item: ContentDatabaseItem) => void;
10046
- onDeletedPreviewItem: (item: ContentDatabaseItem) => boolean;
10047
- onOpenPage: (item: ContentDatabaseItem) => void;
10048
- }) {
10049
- return (
10050
- <section className="col-span-full grid gap-3">
10051
- <DatabaseGroupHeader
10052
- group={group}
10053
- collapsed={collapsed}
10054
- onCollapsedChange={onCollapsedChange}
10055
- />
10056
- {!collapsed ? (
10057
- <div className="content-database-gallery-grid grid gap-3">
10058
- {group.items.map((item, index) => (
10059
- <DatabaseGalleryCard
10060
- key={`${group.id}-${item.id}`}
10061
- item={item}
10062
- properties={properties}
10063
- databaseDocumentId={databaseDocumentId}
10064
- canEdit={canEdit}
10065
- rowIndex={index}
10066
- canReorder={false}
10067
- canMoveUp={false}
10068
- canMoveDown={false}
10069
- onPreviewItem={onPreview}
10070
- onDeletedPreviewItem={onDeletedPreviewItem}
10071
- onPreview={() => onPreview(item)}
10072
- onOpenPage={() => onOpenPage(item)}
10073
- />
10074
- ))}
10075
- {canEdit ? (
10076
- <NewGalleryCard
10077
- disabled={isCreating}
10078
- isPending={isCreating}
10079
- onCreate={(title) => onCreateRow(group, title)}
10080
- />
10081
- ) : null}
10082
- </div>
10083
- ) : null}
10084
- </section>
10085
- );
10086
- }
10087
-
10088
- function DatabaseGalleryCard({
10089
- item,
10090
- properties,
10091
- databaseDocumentId,
10092
- canEdit,
10093
- rowIndex,
10094
- canReorder,
10095
- canMoveUp,
10096
- canMoveDown,
10097
- onPreviewItem,
10098
- onDeletedPreviewItem,
10099
- onPreview,
10100
- onOpenPage,
10101
- }: {
10102
- item: ContentDatabaseItem;
10103
- properties: DocumentProperty[];
10104
- databaseDocumentId: string;
10105
- canEdit: boolean;
10106
- rowIndex: number;
10107
- canReorder: boolean;
10108
- canMoveUp: boolean;
10109
- canMoveDown: boolean;
10110
- onPreviewItem: (item: ContentDatabaseItem) => void;
10111
- onDeletedPreviewItem: (item: ContentDatabaseItem) => boolean;
10112
- onPreview: () => void;
10113
- onOpenPage: () => void;
10114
- }) {
10115
- const visibleProperties = properties.slice(0, 4);
10116
-
10117
- return (
10118
- <div className="group overflow-hidden rounded-md border border-border bg-background shadow-sm transition-colors hover:bg-accent/40">
10119
- <button
10120
- type="button"
10121
- className="block w-full text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
10122
- onClick={onPreview}
10123
- >
10124
- <div className="flex aspect-[5/3] items-center justify-center border-b border-border bg-muted/45">
10125
- <DatabaseItemPageIcon
10126
- document={item.document}
10127
- className="size-10 text-4xl"
10128
- fallbackClassName="size-8 text-muted-foreground/70"
10129
- />
10130
- </div>
10131
- <div className="grid gap-2 p-3">
10132
- <span className="min-w-0 truncate text-sm font-medium">
10133
- {item.document.title || "Untitled"}
10134
- </span>
10135
- {visibleProperties.length > 0 ? (
10136
- <span className="grid gap-1">
10137
- {visibleProperties.map((property) => {
10138
- const itemProperty =
10139
- item.properties.find(
10140
- (candidate) =>
10141
- candidate.definition.id === property.definition.id,
10142
- ) ?? property;
10143
- const Icon = TYPE_ICONS[property.definition.type];
10144
- return (
10145
- <span
10146
- key={property.definition.id}
10147
- className="flex min-w-0 items-center gap-1.5 text-xs text-muted-foreground"
10148
- >
10149
- <Icon className="size-3.5 shrink-0" />
10150
- <span className="truncate">
10151
- {displayValue(itemProperty)}
10152
- </span>
10153
- </span>
10154
- );
10155
- })}
10156
- </span>
10157
- ) : null}
10158
- </div>
10159
- </button>
10160
- {canEdit ? (
10161
- <div className="flex justify-end border-t border-border/70 px-2 py-1">
10162
- <RowActionsCell
10163
- item={item}
10164
- databaseDocumentId={databaseDocumentId}
10165
- rowIndex={rowIndex}
10166
- canReorder={canReorder}
10167
- canMoveUp={canMoveUp}
10168
- canMoveDown={canMoveDown}
10169
- onPreviewItem={onPreviewItem}
10170
- onDeletedPreviewItem={onDeletedPreviewItem}
10171
- onOpenPage={onOpenPage}
10172
- />
10173
- </div>
10174
- ) : null}
10175
- </div>
10176
- );
10177
- }
10178
-
10179
- function NewGalleryCard({
10180
- disabled,
10181
- isPending,
10182
- onCreate,
10183
- }: {
10184
- disabled: boolean;
10185
- isPending: boolean;
10186
- onCreate: CreateDatabaseRowHandler;
10187
- }) {
10188
- const inputRef = useRef<HTMLInputElement>(null);
10189
- const [title, setTitle] = useState("");
10190
-
10191
- async function submitNewCard() {
10192
- if (disabled) return;
10193
- const createdItem = await onCreate(title.trim());
10194
- setTitle("");
10195
- if (!createdItem) inputRef.current?.focus();
10196
- }
10197
-
10198
- return (
10199
- <form
10200
- className="flex min-h-40 flex-col justify-between rounded-md border border-dashed border-border bg-muted/20 p-3 text-sm text-muted-foreground hover:bg-muted/35 focus-within:bg-muted/35"
10201
- onSubmit={(event) => {
10202
- event.preventDefault();
10203
- void submitNewCard();
10204
- }}
10205
- >
10206
- <div className="flex items-center gap-2">
10207
- {isPending ? (
10208
- <Spinner className="size-4 shrink-0" />
10209
- ) : (
10210
- <IconPlus className="size-4 shrink-0" />
10211
- )}
10212
- <input
10213
- ref={inputRef}
10214
- value={title}
10215
- disabled={disabled}
10216
- aria-label={dbText("newDatabaseGalleryCardTitle")}
10217
- placeholder={dbText("newPage")}
10218
- onChange={(event) => setTitle(event.target.value)}
10219
- onKeyDown={(event) => {
10220
- if (event.key === "Enter") {
10221
- event.preventDefault();
10222
- void submitNewCard();
10223
- }
10224
- if (event.key === "Escape") {
10225
- setTitle("");
10226
- event.currentTarget.blur();
10227
- }
10228
- }}
10229
- className="h-7 min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground focus:placeholder:text-muted-foreground/70"
10230
- />
10231
- </div>
10232
- </form>
10233
- );
10234
- }
10235
-
10236
- function DatabaseCalendarView({
10237
- activeView,
10238
- properties,
10239
- items,
10240
- databaseDocumentId,
10241
- canEdit,
10242
- isLoading,
10243
- isCreating,
10244
- activeFilters,
10245
- hasSearch,
10246
- dateProperty,
10247
- month,
10248
- onClearResultConstraints,
10249
- onMonthChange,
10250
- onDatePropertyChange,
10251
- onCreateCard,
10252
- onPreview,
10253
- onDeletedPreviewItem,
10254
- onOpenPage,
10255
- }: {
10256
- activeView: ContentDatabaseView;
10257
- properties: DocumentProperty[];
10258
- items: ContentDatabaseItem[];
10259
- databaseDocumentId: string;
10260
- canEdit: boolean;
10261
- isLoading: boolean;
10262
- isCreating: boolean;
10263
- activeFilters: DatabaseFilter[];
10264
- hasSearch: boolean;
10265
- dateProperty: DocumentProperty | null;
10266
- month: Date;
10267
- onClearResultConstraints: () => void;
10268
- onMonthChange: (month: Date) => void;
10269
- onDatePropertyChange: (propertyId: string | null) => void;
10270
- onCreateCard: (
10271
- dateKey: string,
10272
- title?: string,
10273
- ) => Promise<ContentDatabaseItem | null>;
10274
- onPreview: (item: ContentDatabaseItem) => void;
10275
- onDeletedPreviewItem: (item: ContentDatabaseItem) => boolean;
10276
- onOpenPage: (item: ContentDatabaseItem) => void;
10277
- }) {
10278
- const dateProperties = databaseCalendarDateProperties(properties);
10279
- const monthDays = databaseCalendarMonthDays(month);
10280
- const itemsByDate = databaseCalendarItemsByDate(
10281
- items,
10282
- properties,
10283
- dateProperty?.definition.id ?? null,
10284
- );
10285
- const noDateItems = databaseItemsWithoutDateValue(
10286
- items,
10287
- properties,
10288
- dateProperty?.definition.id ?? null,
10289
- );
10290
- const visibleProperties = properties
10291
- .filter((property) =>
10292
- isDatabasePropertyVisibleInView(property, items, activeView),
10293
- )
10294
- .filter(
10295
- (property) => property.definition.id !== dateProperty?.definition.id,
10296
- );
10297
- const canCreateOnDay =
10298
- canEdit &&
10299
- dateProperty?.editable &&
10300
- dateProperty.definition.type === "date";
10301
- const monthLabel = month.toLocaleDateString(undefined, {
10302
- month: "long",
10303
- year: "numeric",
10304
- });
10305
-
10306
- function changeMonth(offset: number) {
10307
- onMonthChange(
10308
- startOfMonth(new Date(month.getFullYear(), month.getMonth() + offset)),
10309
- );
10310
- }
10311
-
10312
- return (
10313
- <div className="min-w-0 max-w-full overflow-hidden border-b border-border">
10314
- <div className="flex min-h-9 min-w-0 flex-wrap items-center justify-between gap-2 border-t border-border px-1 py-1">
10315
- <div className="flex min-w-0 items-center gap-2 text-xs text-muted-foreground">
10316
- <IconCalendar className="size-4 shrink-0" />
10317
- <span className="truncate">{monthLabel}</span>
10318
- </div>
10319
- <div className="flex min-w-0 flex-wrap items-center justify-end gap-1">
10320
- {dateProperties.length > 0 ? (
10321
- <DropdownMenu>
10322
- <DropdownMenuTrigger asChild>
10323
- <Button
10324
- type="button"
10325
- variant="ghost"
10326
- size="sm"
10327
- className="h-7 max-w-48 gap-1.5 px-2 text-xs text-muted-foreground"
10328
- >
10329
- <IconCalendarDue className="size-3.5 shrink-0" />
10330
- <span className="truncate">
10331
- {dateProperty?.definition.name ?? "Date"}
10332
- </span>
10333
- <IconChevronDown className="size-3.5 shrink-0" />
10334
- </Button>
10335
- </DropdownMenuTrigger>
10336
- <DropdownMenuContent align="end" className="w-56">
10337
- <DropdownMenuLabel className="text-xs text-muted-foreground">
10338
- {dbText("calendarBy")}
10339
- </DropdownMenuLabel>
10340
- {dateProperties.map((property) => {
10341
- const Icon = TYPE_ICONS[property.definition.type];
10342
- return (
10343
- <DropdownMenuItem
10344
- key={property.definition.id}
10345
- onSelect={(event) => {
10346
- event.preventDefault();
10347
- onDatePropertyChange(property.definition.id);
10348
- }}
10349
- >
10350
- <Icon className="mr-2 size-4 text-muted-foreground" />
10351
- <span className="min-w-0 flex-1 truncate">
10352
- {property.definition.name}
10353
- </span>
10354
- {dateProperty?.definition.id ===
10355
- property.definition.id ? (
10356
- <IconCheck className="size-4 text-muted-foreground" />
10357
- ) : null}
10358
- </DropdownMenuItem>
10359
- );
10360
- })}
10361
- </DropdownMenuContent>
10362
- </DropdownMenu>
10363
- ) : null}
10364
- <Button
10365
- type="button"
10366
- variant="ghost"
10367
- size="sm"
10368
- className="h-7 px-2 text-xs text-muted-foreground"
10369
- onClick={() => onMonthChange(startOfMonth(new Date()))}
10370
- >
10371
- <IconCalendarEvent className="mr-1 size-3.5" />
10372
- Today
10373
- </Button>
10374
- <Button
10375
- type="button"
10376
- variant="ghost"
10377
- size="icon"
10378
- className="size-7 text-muted-foreground"
10379
- aria-label={dbText("previousMonth")}
10380
- onClick={() => changeMonth(-1)}
10381
- >
10382
- <IconArrowUp className="size-3.5 -rotate-90" />
10383
- </Button>
10384
- <Button
10385
- type="button"
10386
- variant="ghost"
10387
- size="icon"
10388
- className="size-7 text-muted-foreground"
10389
- aria-label={dbText("nextMonth")}
10390
- onClick={() => changeMonth(1)}
10391
- >
10392
- <IconArrowUp className="size-3.5 rotate-90" />
10393
- </Button>
10394
- </div>
10395
- </div>
10396
-
10397
- {isLoading ? (
10398
- <div className="flex h-16 items-center gap-2 px-2 text-sm text-muted-foreground">
10399
- <Spinner className="size-4" />
10400
- {dbText("loadingCalendar")}
10401
- </div>
10402
- ) : dateProperties.length === 0 ? (
10403
- <div className="flex min-h-24 items-center justify-between gap-3 px-2 py-4 text-sm text-muted-foreground">
10404
- <span>{dbText("addADatePropertyToUseCalendarView")}</span>
10405
- {canEdit ? <AddProperty documentId={databaseDocumentId} /> : null}
10406
- </div>
10407
- ) : databaseViewHasNoMatchingPages(
10408
- items.length,
10409
- hasSearch,
10410
- activeFilters.length,
10411
- ) ? (
10412
- <DatabaseNoMatchingPages onClear={onClearResultConstraints} />
10413
- ) : (
10414
- <>
10415
- <div
10416
- data-database-calendar-surface="true"
10417
- className="min-w-0 max-w-full overflow-hidden"
10418
- >
10419
- <div className="w-full min-w-0">
10420
- <div className="grid grid-cols-7 border-t border-border text-xs font-medium text-muted-foreground">
10421
- {CALENDAR_WEEKDAYS.map((weekday) => (
10422
- <div
10423
- key={weekday}
10424
- className="min-w-0 border-r border-border px-2 py-1.5 last:border-r-0"
10425
- >
10426
- {weekday}
10427
- </div>
10428
- ))}
10429
- </div>
10430
- <div className="grid grid-cols-7 border-t border-border">
10431
- {monthDays.map((day) => {
10432
- const dateKey = calendarDateKey(day);
10433
- const dayItems = itemsByDate.get(dateKey) ?? [];
10434
- const inMonth = day.getMonth() === month.getMonth();
10435
- return (
10436
- <section
10437
- key={dateKey}
10438
- className={cn(
10439
- "group min-w-0 border-r border-b border-border bg-background p-1.5 last:border-r-0",
10440
- !inMonth && "bg-muted/25 text-muted-foreground",
10441
- )}
10442
- aria-label={`${dateKey} calendar day`}
10443
- >
10444
- <div className="mb-1 flex h-6 items-center justify-between gap-1">
10445
- {dayItems.length > 0 ? (
10446
- <span className="rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground">
10447
- {dayItems.length}
10448
- </span>
10449
- ) : (
10450
- <span aria-hidden="true" />
10451
- )}
10452
- <span className="ml-auto flex items-center gap-1">
10453
- {canCreateOnDay ? (
10454
- <NewCalendarCard
10455
- dateKey={dateKey}
10456
- disabled={isCreating}
10457
- isPending={isCreating}
10458
- onCreate={onCreateCard}
10459
- />
10460
- ) : null}
10461
- <span
10462
- className={cn(
10463
- "flex size-6 items-center justify-center rounded-full text-xs font-medium",
10464
- dateKey === calendarDateKey(new Date()) &&
10465
- "bg-foreground text-background",
10466
- )}
10467
- >
10468
- {day.getDate()}
10469
- </span>
10470
- </span>
10471
- </div>
10472
- <div className="grid min-h-28 gap-1">
10473
- {dayItems.map((item) => (
10474
- <DatabaseCalendarCard
10475
- key={item.id}
10476
- item={item}
10477
- databaseDocumentId={databaseDocumentId}
10478
- properties={visibleProperties}
10479
- canEdit={canEdit}
10480
- onPreviewItem={onPreview}
10481
- onDeletedPreviewItem={onDeletedPreviewItem}
10482
- onPreview={() => onPreview(item)}
10483
- onOpenPage={() => onOpenPage(item)}
10484
- />
10485
- ))}
10486
- </div>
10487
- </section>
10488
- );
10489
- })}
10490
- </div>
10491
- </div>
10492
- </div>
10493
- <DatabaseDateViewNoDateSection
10494
- items={noDateItems}
10495
- databaseDocumentId={databaseDocumentId}
10496
- properties={visibleProperties}
10497
- canEdit={canEdit}
10498
- onPreview={onPreview}
10499
- onDeletedPreviewItem={onDeletedPreviewItem}
10500
- onOpenPage={onOpenPage}
10501
- />
10502
- </>
10503
- )}
10504
- </div>
10505
- );
10506
- }
10507
-
10508
- function DatabaseDateViewNoDateSection({
10509
- items,
10510
- databaseDocumentId,
10511
- properties,
10512
- canEdit,
10513
- onPreview,
10514
- onDeletedPreviewItem,
10515
- onOpenPage,
10516
- }: {
10517
- items: ContentDatabaseItem[];
10518
- databaseDocumentId: string;
10519
- properties: DocumentProperty[];
10520
- canEdit: boolean;
10521
- onPreview: (item: ContentDatabaseItem) => void;
10522
- onDeletedPreviewItem: (item: ContentDatabaseItem) => boolean;
10523
- onOpenPage: (item: ContentDatabaseItem) => void;
10524
- }) {
10525
- if (items.length === 0) return null;
10526
-
10527
- return (
10528
- <section className="border-t border-border bg-muted/20 px-2 py-2">
10529
- <div className="mb-2 flex items-center justify-between gap-2 text-xs text-muted-foreground">
10530
- <span className="flex min-w-0 items-center gap-1.5 font-medium">
10531
- <IconCalendarOff className="size-3.5 shrink-0" />
10532
- <span className="truncate">{dbText("noDate")}</span>
10533
- </span>
10534
- <span className="rounded bg-background px-1.5 py-0.5 text-[11px]">
10535
- {items.length}
10536
- </span>
10537
- </div>
10538
- <div className="content-database-calendar-undated-grid grid gap-1">
10539
- {items.map((item) => (
10540
- <DatabaseCalendarCard
10541
- key={item.id}
10542
- item={item}
10543
- databaseDocumentId={databaseDocumentId}
10544
- properties={properties}
10545
- canEdit={canEdit}
10546
- onPreviewItem={onPreview}
10547
- onDeletedPreviewItem={onDeletedPreviewItem}
10548
- onPreview={() => onPreview(item)}
10549
- onOpenPage={() => onOpenPage(item)}
10550
- />
10551
- ))}
10552
- </div>
10553
- </section>
10554
- );
10555
- }
10556
-
10557
- function DatabaseCalendarCard({
10558
- item,
10559
- databaseDocumentId,
10560
- properties,
10561
- canEdit,
10562
- onPreviewItem,
10563
- onDeletedPreviewItem,
10564
- onPreview,
10565
- onOpenPage,
10566
- }: {
10567
- item: ContentDatabaseItem;
10568
- databaseDocumentId: string;
10569
- properties: DocumentProperty[];
10570
- canEdit: boolean;
10571
- onPreviewItem: (item: ContentDatabaseItem) => void;
10572
- onDeletedPreviewItem: (item: ContentDatabaseItem) => boolean;
10573
- onPreview: () => void;
10574
- onOpenPage: () => void;
10575
- }) {
10576
- const visibleProperties = properties.slice(0, 2);
10577
-
10578
- return (
10579
- <div className="group/card rounded border border-border bg-background px-2 py-1.5 text-xs shadow-sm transition-colors hover:bg-accent/60">
10580
- <div className="flex min-w-0 items-start gap-1">
10581
- <button
10582
- type="button"
10583
- className="grid min-w-0 flex-1 gap-1 rounded text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
10584
- onClick={onPreview}
10585
- >
10586
- <span className="flex min-w-0 items-center gap-1.5 font-medium">
10587
- <DatabaseItemPageIcon
10588
- document={item.document}
10589
- className="size-3.5 text-xs"
10590
- fallbackClassName="size-3.5"
10591
- />
10592
- <span className="truncate">
10593
- {item.document.title || "Untitled"}
10594
- </span>
10595
- </span>
10596
- {visibleProperties.length > 0 ? (
10597
- <span className="grid gap-0.5">
10598
- {visibleProperties.map((property) => {
10599
- const itemProperty =
10600
- item.properties.find(
10601
- (candidate) =>
10602
- candidate.definition.id === property.definition.id,
10603
- ) ?? property;
10604
- const Icon = TYPE_ICONS[property.definition.type];
10605
- return (
10606
- <span
10607
- key={property.definition.id}
10608
- className="flex min-w-0 items-center gap-1 text-muted-foreground"
10609
- >
10610
- <Icon className="size-3 shrink-0" />
10611
- <span className="truncate">
10612
- {displayValue(itemProperty)}
10613
- </span>
10614
- </span>
10615
- );
10616
- })}
10617
- </span>
10618
- ) : null}
10619
- </button>
10620
- {canEdit ? (
10621
- <RowActionsCell
10622
- item={item}
10623
- databaseDocumentId={databaseDocumentId}
10624
- rowIndex={0}
10625
- canReorder={false}
10626
- canMoveUp={false}
10627
- canMoveDown={false}
10628
- showReorderActions={false}
10629
- onPreviewItem={onPreviewItem}
10630
- onDeletedPreviewItem={onDeletedPreviewItem}
10631
- onOpenPage={onOpenPage}
10632
- />
10633
- ) : null}
10634
- </div>
10635
- </div>
10636
- );
10637
- }
10638
- function NewCalendarCard({
10639
- dateKey,
10640
- disabled,
10641
- isPending,
10642
- onCreate,
9528
+ export function DatabaseGroupHeader({
9529
+ group,
9530
+ collapsed,
9531
+ onCollapsedChange,
10643
9532
  }: {
10644
- dateKey: string;
10645
- disabled: boolean;
10646
- isPending: boolean;
10647
- onCreate: (
10648
- dateKey: string,
10649
- title?: string,
10650
- ) => Promise<ContentDatabaseItem | null>;
9533
+ group: DatabaseBoardGroup;
9534
+ collapsed: boolean;
9535
+ onCollapsedChange: (collapsed: boolean) => void;
10651
9536
  }) {
10652
- async function createCard() {
10653
- if (disabled) return;
10654
- await onCreate(dateKey, "");
10655
- }
10656
-
10657
9537
  return (
10658
9538
  <button
10659
9539
  type="button"
10660
- aria-label={`Add page for ${dateKey}`}
10661
- disabled={disabled}
10662
- className="flex size-6 shrink-0 items-center justify-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-muted hover:text-foreground hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40 group-focus-within:opacity-100 group-hover:opacity-100"
10663
- onClick={() => void createCard()}
9540
+ className="flex min-h-9 w-full items-center gap-2 border-t border-border bg-muted/30 px-2 text-left text-xs text-muted-foreground hover:bg-muted/45 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
9541
+ aria-expanded={!collapsed}
9542
+ onClick={() => onCollapsedChange(!collapsed)}
10664
9543
  >
10665
- {isPending ? (
10666
- <Spinner className="size-3.5" />
10667
- ) : (
10668
- <IconPlus className="size-3.5" />
10669
- )}
9544
+ <IconChevronRight
9545
+ className={cn(
9546
+ "size-3.5 shrink-0 transition-transform",
9547
+ !collapsed && "rotate-90",
9548
+ )}
9549
+ />
9550
+ <span className="min-w-0 truncate font-medium text-foreground">
9551
+ {group.label}
9552
+ </span>
9553
+ <span className="rounded bg-background px-1.5 py-0.5 text-[11px]">
9554
+ {group.items.length}
9555
+ </span>
10670
9556
  </button>
10671
9557
  );
10672
9558
  }
10673
9559
 
10674
- function DatabaseTimelineView({
9560
+ function DatabaseCalendarView({
10675
9561
  activeView,
10676
9562
  properties,
10677
9563
  items,
@@ -10686,7 +9572,6 @@ function DatabaseTimelineView({
10686
9572
  onClearResultConstraints,
10687
9573
  onMonthChange,
10688
9574
  onDatePropertyChange,
10689
- onEndDatePropertyChange,
10690
9575
  onCreateCard,
10691
9576
  onPreview,
10692
9577
  onDeletedPreviewItem,
@@ -10706,7 +9591,6 @@ function DatabaseTimelineView({
10706
9591
  onClearResultConstraints: () => void;
10707
9592
  onMonthChange: (month: Date) => void;
10708
9593
  onDatePropertyChange: (propertyId: string | null) => void;
10709
- onEndDatePropertyChange: (propertyId: string | null) => void;
10710
9594
  onCreateCard: (
10711
9595
  dateKey: string,
10712
9596
  title?: string,
@@ -10716,18 +9600,11 @@ function DatabaseTimelineView({
10716
9600
  onOpenPage: (item: ContentDatabaseItem) => void;
10717
9601
  }) {
10718
9602
  const dateProperties = databaseCalendarDateProperties(properties);
10719
- const timelineDays = databaseTimelineDays(month);
10720
- const endDateProperty = databaseTimelineEndDateProperty(
10721
- activeView,
10722
- properties,
10723
- dateProperty?.definition.id ?? null,
10724
- );
10725
- const timelineSpans = databaseTimelineItemSpans(
9603
+ const monthDays = databaseCalendarMonthDays(month);
9604
+ const itemsByDate = databaseCalendarItemsByDate(
10726
9605
  items,
10727
9606
  properties,
10728
9607
  dateProperty?.definition.id ?? null,
10729
- endDateProperty?.definition.id ?? null,
10730
- timelineDays,
10731
9608
  );
10732
9609
  const noDateItems = databaseItemsWithoutDateValue(
10733
9610
  items,
@@ -10739,15 +9616,16 @@ function DatabaseTimelineView({
10739
9616
  isDatabasePropertyVisibleInView(property, items, activeView),
10740
9617
  )
10741
9618
  .filter(
10742
- (property) =>
10743
- property.definition.id !== dateProperty?.definition.id &&
10744
- property.definition.id !== endDateProperty?.definition.id,
9619
+ (property) => property.definition.id !== dateProperty?.definition.id,
10745
9620
  );
10746
9621
  const canCreateOnDay =
10747
9622
  canEdit &&
10748
9623
  dateProperty?.editable &&
10749
9624
  dateProperty.definition.type === "date";
10750
- const rangeLabel = databaseTimelineRangeLabel(timelineDays);
9625
+ const monthLabel = month.toLocaleDateString(undefined, {
9626
+ month: "long",
9627
+ year: "numeric",
9628
+ });
10751
9629
 
10752
9630
  function changeMonth(offset: number) {
10753
9631
  onMonthChange(
@@ -10756,57 +9634,13 @@ function DatabaseTimelineView({
10756
9634
  }
10757
9635
 
10758
9636
  return (
10759
- <div className="border-b border-border">
10760
- <div className="flex min-h-9 flex-wrap items-center justify-between gap-2 border-t border-border px-1 py-1">
9637
+ <div className="min-w-0 max-w-full overflow-hidden border-b border-border">
9638
+ <div className="flex min-h-9 min-w-0 flex-wrap items-center justify-between gap-2 border-t border-border px-1 py-1">
10761
9639
  <div className="flex min-w-0 items-center gap-2 text-xs text-muted-foreground">
10762
- <IconTimeline className="size-4 shrink-0" />
10763
- <span className="truncate">{rangeLabel}</span>
9640
+ <IconCalendar className="size-4 shrink-0" />
9641
+ <span className="truncate">{monthLabel}</span>
10764
9642
  </div>
10765
- <div className="flex min-w-0 items-center gap-1">
10766
- {dateProperties.length > 0 ? (
10767
- <DropdownMenu>
10768
- <DropdownMenuTrigger asChild>
10769
- <Button
10770
- type="button"
10771
- variant="ghost"
10772
- size="sm"
10773
- className="h-7 max-w-48 gap-1.5 px-2 text-xs text-muted-foreground"
10774
- >
10775
- <IconCalendarDue className="size-3.5 shrink-0" />
10776
- <span className="truncate">
10777
- {dateProperty?.definition.name ?? "Date"}
10778
- </span>
10779
- <IconChevronDown className="size-3.5 shrink-0" />
10780
- </Button>
10781
- </DropdownMenuTrigger>
10782
- <DropdownMenuContent align="end" className="w-56">
10783
- <DropdownMenuLabel className="text-xs text-muted-foreground">
10784
- {dbText("startDate")}
10785
- </DropdownMenuLabel>
10786
- {dateProperties.map((property) => {
10787
- const Icon = TYPE_ICONS[property.definition.type];
10788
- return (
10789
- <DropdownMenuItem
10790
- key={property.definition.id}
10791
- onSelect={(event) => {
10792
- event.preventDefault();
10793
- onDatePropertyChange(property.definition.id);
10794
- }}
10795
- >
10796
- <Icon className="mr-2 size-4 text-muted-foreground" />
10797
- <span className="min-w-0 flex-1 truncate">
10798
- {property.definition.name}
10799
- </span>
10800
- {dateProperty?.definition.id ===
10801
- property.definition.id ? (
10802
- <IconCheck className="size-4 text-muted-foreground" />
10803
- ) : null}
10804
- </DropdownMenuItem>
10805
- );
10806
- })}
10807
- </DropdownMenuContent>
10808
- </DropdownMenu>
10809
- ) : null}
9643
+ <div className="flex min-w-0 flex-wrap items-center justify-end gap-1">
10810
9644
  {dateProperties.length > 0 ? (
10811
9645
  <DropdownMenu>
10812
9646
  <DropdownMenuTrigger asChild>
@@ -10816,56 +9650,38 @@ function DatabaseTimelineView({
10816
9650
  size="sm"
10817
9651
  className="h-7 max-w-48 gap-1.5 px-2 text-xs text-muted-foreground"
10818
9652
  >
10819
- <IconTimeline className="size-3.5 shrink-0" />
10820
- <span className="truncate">
10821
- End: {endDateProperty?.definition.name ?? "None"}
10822
- </span>
10823
- <IconChevronDown className="size-3.5 shrink-0" />
10824
- </Button>
10825
- </DropdownMenuTrigger>
10826
- <DropdownMenuContent align="end" className="w-56">
10827
- <DropdownMenuLabel className="text-xs text-muted-foreground">
10828
- {dbText("endDate")}
10829
- </DropdownMenuLabel>
10830
- <DropdownMenuItem
10831
- onSelect={(event) => {
10832
- event.preventDefault();
10833
- onEndDatePropertyChange(null);
10834
- }}
10835
- >
10836
- <span className="min-w-0 flex-1 truncate">
10837
- {dbText("noEndDate")}
10838
- </span>
10839
- {!endDateProperty ? (
10840
- <IconCheck className="size-4 text-muted-foreground" />
10841
- ) : null}
10842
- </DropdownMenuItem>
10843
- {dateProperties
10844
- .filter(
10845
- (property) =>
10846
- property.definition.id !== dateProperty?.definition.id,
10847
- )
10848
- .map((property) => {
10849
- const Icon = TYPE_ICONS[property.definition.type];
10850
- return (
10851
- <DropdownMenuItem
10852
- key={property.definition.id}
10853
- onSelect={(event) => {
10854
- event.preventDefault();
10855
- onEndDatePropertyChange(property.definition.id);
10856
- }}
10857
- >
10858
- <Icon className="mr-2 size-4 text-muted-foreground" />
10859
- <span className="min-w-0 flex-1 truncate">
10860
- {property.definition.name}
10861
- </span>
10862
- {endDateProperty?.definition.id ===
10863
- property.definition.id ? (
10864
- <IconCheck className="size-4 text-muted-foreground" />
10865
- ) : null}
10866
- </DropdownMenuItem>
10867
- );
10868
- })}
9653
+ <IconCalendarDue className="size-3.5 shrink-0" />
9654
+ <span className="truncate">
9655
+ {dateProperty?.definition.name ?? "Date"}
9656
+ </span>
9657
+ <IconChevronDown className="size-3.5 shrink-0" />
9658
+ </Button>
9659
+ </DropdownMenuTrigger>
9660
+ <DropdownMenuContent align="end" className="w-56">
9661
+ <DropdownMenuLabel className="text-xs text-muted-foreground">
9662
+ {dbText("calendarBy")}
9663
+ </DropdownMenuLabel>
9664
+ {dateProperties.map((property) => {
9665
+ const Icon = TYPE_ICONS[property.definition.type];
9666
+ return (
9667
+ <DropdownMenuItem
9668
+ key={property.definition.id}
9669
+ onSelect={(event) => {
9670
+ event.preventDefault();
9671
+ onDatePropertyChange(property.definition.id);
9672
+ }}
9673
+ >
9674
+ <Icon className="mr-2 size-4 text-muted-foreground" />
9675
+ <span className="min-w-0 flex-1 truncate">
9676
+ {property.definition.name}
9677
+ </span>
9678
+ {dateProperty?.definition.id ===
9679
+ property.definition.id ? (
9680
+ <IconCheck className="size-4 text-muted-foreground" />
9681
+ ) : null}
9682
+ </DropdownMenuItem>
9683
+ );
9684
+ })}
10869
9685
  </DropdownMenuContent>
10870
9686
  </DropdownMenu>
10871
9687
  ) : null}
@@ -10884,7 +9700,7 @@ function DatabaseTimelineView({
10884
9700
  variant="ghost"
10885
9701
  size="icon"
10886
9702
  className="size-7 text-muted-foreground"
10887
- aria-label={dbText("previousTimelineRange")}
9703
+ aria-label={dbText("previousMonth")}
10888
9704
  onClick={() => changeMonth(-1)}
10889
9705
  >
10890
9706
  <IconArrowUp className="size-3.5 -rotate-90" />
@@ -10894,7 +9710,7 @@ function DatabaseTimelineView({
10894
9710
  variant="ghost"
10895
9711
  size="icon"
10896
9712
  className="size-7 text-muted-foreground"
10897
- aria-label={dbText("nextTimelineRange")}
9713
+ aria-label={dbText("nextMonth")}
10898
9714
  onClick={() => changeMonth(1)}
10899
9715
  >
10900
9716
  <IconArrowUp className="size-3.5 rotate-90" />
@@ -10905,140 +9721,97 @@ function DatabaseTimelineView({
10905
9721
  {isLoading ? (
10906
9722
  <div className="flex h-16 items-center gap-2 px-2 text-sm text-muted-foreground">
10907
9723
  <Spinner className="size-4" />
10908
- {dbText("loadingTimeline")}
9724
+ {dbText("loadingCalendar")}
10909
9725
  </div>
10910
9726
  ) : dateProperties.length === 0 ? (
10911
9727
  <div className="flex min-h-24 items-center justify-between gap-3 px-2 py-4 text-sm text-muted-foreground">
10912
- <span>{dbText("addADatePropertyToUseTimelineView")}</span>
9728
+ <span>{dbText("addADatePropertyToUseCalendarView")}</span>
10913
9729
  {canEdit ? <AddProperty documentId={databaseDocumentId} /> : null}
10914
9730
  </div>
9731
+ ) : databaseViewHasNoMatchingPages(
9732
+ items.length,
9733
+ hasSearch,
9734
+ activeFilters.length,
9735
+ ) ? (
9736
+ <DatabaseNoMatchingPages onClear={onClearResultConstraints} />
10915
9737
  ) : (
10916
9738
  <>
10917
- <div className="overflow-x-auto border-t border-border">
10918
- <div
10919
- className="grid min-w-max"
10920
- style={{
10921
- gridTemplateColumns: `repeat(${timelineDays.length}, minmax(8rem, 1fr))`,
10922
- gridTemplateRows: `auto repeat(${Math.max(timelineSpans.length, 1)}, minmax(3.25rem, auto)) auto minmax(0.75rem, auto)`,
10923
- }}
10924
- >
10925
- {timelineDays.map((day, index) => {
10926
- const dateKey = calendarDateKey(day);
10927
- const inMonth = day.getMonth() === month.getMonth();
10928
- return (
10929
- <div
10930
- key={dateKey}
10931
- className={cn(
10932
- "border-r border-border bg-background last:border-r-0",
10933
- !inMonth && "bg-muted/25",
10934
- )}
10935
- style={{
10936
- gridColumn: index + 1,
10937
- gridRow: `1 / ${Math.max(timelineSpans.length, 1) + 4}`,
10938
- }}
10939
- aria-label={`${dateKey} timeline day`}
10940
- />
10941
- );
10942
- })}
10943
- {timelineDays.map((day, index) => {
10944
- const dateKey = calendarDateKey(day);
10945
- const inMonth = day.getMonth() === month.getMonth();
10946
- return (
9739
+ <div
9740
+ data-database-calendar-surface="true"
9741
+ className="min-w-0 max-w-full overflow-hidden"
9742
+ >
9743
+ <div className="w-full min-w-0">
9744
+ <div className="grid grid-cols-7 border-t border-border text-xs font-medium text-muted-foreground">
9745
+ {CALENDAR_WEEKDAYS.map((weekday) => (
10947
9746
  <div
10948
- key={`${dateKey}-header`}
10949
- className={cn(
10950
- "sticky top-0 z-10 grid gap-0.5 border-r border-b border-border bg-background px-2 py-2 last:border-r-0",
10951
- !inMonth && "bg-muted/70",
10952
- )}
10953
- style={{ gridColumn: index + 1, gridRow: 1 }}
9747
+ key={weekday}
9748
+ className="min-w-0 border-r border-border px-2 py-1.5 last:border-r-0"
10954
9749
  >
10955
- <span className="text-[11px] uppercase text-muted-foreground">
10956
- {day.toLocaleDateString(undefined, { weekday: "short" })}
10957
- </span>
10958
- <span
9750
+ {weekday}
9751
+ </div>
9752
+ ))}
9753
+ </div>
9754
+ <div className="grid grid-cols-7 border-t border-border">
9755
+ {monthDays.map((day) => {
9756
+ const dateKey = calendarDateKey(day);
9757
+ const dayItems = itemsByDate.get(dateKey) ?? [];
9758
+ const inMonth = day.getMonth() === month.getMonth();
9759
+ return (
9760
+ <section
9761
+ key={dateKey}
10959
9762
  className={cn(
10960
- "w-fit rounded px-1.5 py-0.5 text-sm font-medium",
10961
- dateKey === calendarDateKey(new Date()) &&
10962
- "bg-foreground text-background",
9763
+ "group min-w-0 border-r border-b border-border bg-background p-1.5 last:border-r-0",
9764
+ !inMonth && "bg-muted/25 text-muted-foreground",
10963
9765
  )}
9766
+ aria-label={`${dateKey} calendar day`}
10964
9767
  >
10965
- {day.toLocaleDateString(undefined, {
10966
- month: "short",
10967
- day: "numeric",
10968
- })}
10969
- </span>
10970
- </div>
10971
- );
10972
- })}
10973
- {timelineSpans.map((span, index) => (
10974
- <div
10975
- key={span.item.id}
10976
- className="z-[1] p-1.5"
10977
- style={{
10978
- gridColumn: `${span.startIndex + 1} / ${span.endIndex + 2}`,
10979
- gridRow: index + 2,
10980
- }}
10981
- >
10982
- <DatabaseTimelineCard
10983
- item={span.item}
10984
- databaseDocumentId={databaseDocumentId}
10985
- dateLabel={span.label}
10986
- properties={visibleProperties}
10987
- canEdit={canEdit}
10988
- onPreviewItem={onPreview}
10989
- onDeletedPreviewItem={onDeletedPreviewItem}
10990
- onPreview={() => onPreview(span.item)}
10991
- onOpenPage={() => onOpenPage(span.item)}
10992
- />
10993
- </div>
10994
- ))}
10995
- {databaseViewHasNoMatchingPages(
10996
- items.length,
10997
- hasSearch,
10998
- activeFilters.length,
10999
- ) ? (
11000
- <div
11001
- className="z-[1] m-1.5"
11002
- style={{
11003
- gridColumn: `1 / ${timelineDays.length + 1}`,
11004
- gridRow: 2,
11005
- }}
11006
- >
11007
- <DatabaseNoMatchingPages
11008
- className="rounded border border-dashed border-border/70 bg-background/80"
11009
- onClear={onClearResultConstraints}
11010
- />
11011
- </div>
11012
- ) : null}
11013
- {canCreateOnDay
11014
- ? timelineDays.map((day, index) => {
11015
- const dateKey = calendarDateKey(day);
11016
- return (
11017
- <div
11018
- key={`${dateKey}-new`}
11019
- className="z-[1] p-1.5"
11020
- style={{
11021
- gridColumn: index + 1,
11022
- gridRow: Math.max(timelineSpans.length, 1) + 2,
11023
- }}
11024
- >
11025
- <NewTimelineCard
11026
- dateKey={dateKey}
11027
- disabled={isCreating}
11028
- isPending={isCreating}
11029
- onCreate={onCreateCard}
11030
- />
9768
+ <div className="mb-1 flex h-6 items-center justify-between gap-1">
9769
+ {dayItems.length > 0 ? (
9770
+ <span className="rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground">
9771
+ {dayItems.length}
9772
+ </span>
9773
+ ) : (
9774
+ <span aria-hidden="true" />
9775
+ )}
9776
+ <span className="ml-auto flex items-center gap-1">
9777
+ {canCreateOnDay ? (
9778
+ <NewCalendarCard
9779
+ dateKey={dateKey}
9780
+ disabled={isCreating}
9781
+ isPending={isCreating}
9782
+ onCreate={onCreateCard}
9783
+ />
9784
+ ) : null}
9785
+ <span
9786
+ className={cn(
9787
+ "flex size-6 items-center justify-center rounded-full text-xs font-medium",
9788
+ dateKey === calendarDateKey(new Date()) &&
9789
+ "bg-foreground text-background",
9790
+ )}
9791
+ >
9792
+ {day.getDate()}
9793
+ </span>
9794
+ </span>
11031
9795
  </div>
11032
- );
11033
- })
11034
- : null}
11035
- <div
11036
- className="min-h-3"
11037
- style={{
11038
- gridColumn: `1 / ${timelineDays.length + 1}`,
11039
- gridRow: Math.max(timelineSpans.length, 1) + 3,
11040
- }}
11041
- />
9796
+ <div className="grid min-h-28 gap-1">
9797
+ {dayItems.map((item) => (
9798
+ <DatabaseCalendarCard
9799
+ key={item.id}
9800
+ item={item}
9801
+ databaseDocumentId={databaseDocumentId}
9802
+ properties={visibleProperties}
9803
+ canEdit={canEdit}
9804
+ onPreviewItem={onPreview}
9805
+ onDeletedPreviewItem={onDeletedPreviewItem}
9806
+ onPreview={() => onPreview(item)}
9807
+ onOpenPage={() => onOpenPage(item)}
9808
+ />
9809
+ ))}
9810
+ </div>
9811
+ </section>
9812
+ );
9813
+ })}
9814
+ </div>
11042
9815
  </div>
11043
9816
  </div>
11044
9817
  <DatabaseDateViewNoDateSection
@@ -11056,10 +9829,58 @@ function DatabaseTimelineView({
11056
9829
  );
11057
9830
  }
11058
9831
 
11059
- function DatabaseTimelineCard({
9832
+ export function DatabaseDateViewNoDateSection({
9833
+ items,
9834
+ databaseDocumentId,
9835
+ properties,
9836
+ canEdit,
9837
+ onPreview,
9838
+ onDeletedPreviewItem,
9839
+ onOpenPage,
9840
+ }: {
9841
+ items: ContentDatabaseItem[];
9842
+ databaseDocumentId: string;
9843
+ properties: DocumentProperty[];
9844
+ canEdit: boolean;
9845
+ onPreview: (item: ContentDatabaseItem) => void;
9846
+ onDeletedPreviewItem: (item: ContentDatabaseItem) => boolean;
9847
+ onOpenPage: (item: ContentDatabaseItem) => void;
9848
+ }) {
9849
+ if (items.length === 0) return null;
9850
+
9851
+ return (
9852
+ <section className="border-t border-border bg-muted/20 px-2 py-2">
9853
+ <div className="mb-2 flex items-center justify-between gap-2 text-xs text-muted-foreground">
9854
+ <span className="flex min-w-0 items-center gap-1.5 font-medium">
9855
+ <IconCalendarOff className="size-3.5 shrink-0" />
9856
+ <span className="truncate">{dbText("noDate")}</span>
9857
+ </span>
9858
+ <span className="rounded bg-background px-1.5 py-0.5 text-[11px]">
9859
+ {items.length}
9860
+ </span>
9861
+ </div>
9862
+ <div className="content-database-calendar-undated-grid grid gap-1">
9863
+ {items.map((item) => (
9864
+ <DatabaseCalendarCard
9865
+ key={item.id}
9866
+ item={item}
9867
+ databaseDocumentId={databaseDocumentId}
9868
+ properties={properties}
9869
+ canEdit={canEdit}
9870
+ onPreviewItem={onPreview}
9871
+ onDeletedPreviewItem={onDeletedPreviewItem}
9872
+ onPreview={() => onPreview(item)}
9873
+ onOpenPage={() => onOpenPage(item)}
9874
+ />
9875
+ ))}
9876
+ </div>
9877
+ </section>
9878
+ );
9879
+ }
9880
+
9881
+ function DatabaseCalendarCard({
11060
9882
  item,
11061
9883
  databaseDocumentId,
11062
- dateLabel,
11063
9884
  properties,
11064
9885
  canEdit,
11065
9886
  onPreviewItem,
@@ -11069,7 +9890,6 @@ function DatabaseTimelineCard({
11069
9890
  }: {
11070
9891
  item: ContentDatabaseItem;
11071
9892
  databaseDocumentId: string;
11072
- dateLabel: string;
11073
9893
  properties: DocumentProperty[];
11074
9894
  canEdit: boolean;
11075
9895
  onPreviewItem: (item: ContentDatabaseItem) => void;
@@ -11080,7 +9900,7 @@ function DatabaseTimelineCard({
11080
9900
  const visibleProperties = properties.slice(0, 2);
11081
9901
 
11082
9902
  return (
11083
- <div className="group/card rounded-md border border-border bg-background px-2 py-2 text-xs shadow-sm transition-colors hover:bg-accent/60">
9903
+ <div className="group/card rounded border border-border bg-background px-2 py-1.5 text-xs shadow-sm transition-colors hover:bg-accent/60">
11084
9904
  <div className="flex min-w-0 items-start gap-1">
11085
9905
  <button
11086
9906
  type="button"
@@ -11097,9 +9917,6 @@ function DatabaseTimelineCard({
11097
9917
  {item.document.title || "Untitled"}
11098
9918
  </span>
11099
9919
  </span>
11100
- <span className="truncate text-[11px] text-muted-foreground">
11101
- {dateLabel}
11102
- </span>
11103
9920
  {visibleProperties.length > 0 ? (
11104
9921
  <span className="grid gap-0.5">
11105
9922
  {visibleProperties.map((property) => {
@@ -11142,8 +9959,7 @@ function DatabaseTimelineCard({
11142
9959
  </div>
11143
9960
  );
11144
9961
  }
11145
-
11146
- function NewTimelineCard({
9962
+ function NewCalendarCard({
11147
9963
  dateKey,
11148
9964
  disabled,
11149
9965
  isPending,
@@ -11157,51 +9973,25 @@ function NewTimelineCard({
11157
9973
  title?: string,
11158
9974
  ) => Promise<ContentDatabaseItem | null>;
11159
9975
  }) {
11160
- const inputRef = useRef<HTMLInputElement>(null);
11161
- const [title, setTitle] = useState("");
11162
-
11163
- async function submitNewCard() {
9976
+ async function createCard() {
11164
9977
  if (disabled) return;
11165
- const createdItem = await onCreate(dateKey, title.trim());
11166
- setTitle("");
11167
- if (!createdItem) inputRef.current?.focus();
9978
+ await onCreate(dateKey, "");
11168
9979
  }
11169
9980
 
11170
9981
  return (
11171
- <form
11172
- className="rounded border border-dashed border-transparent bg-transparent transition-colors focus-within:border-border focus-within:bg-background/80 hover:bg-background/60"
11173
- onSubmit={(event) => {
11174
- event.preventDefault();
11175
- void submitNewCard();
11176
- }}
9982
+ <button
9983
+ type="button"
9984
+ aria-label={`Add page for ${dateKey}`}
9985
+ disabled={disabled}
9986
+ className="flex size-6 shrink-0 items-center justify-center rounded text-muted-foreground opacity-0 transition-opacity hover:bg-muted hover:text-foreground hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-40 group-focus-within:opacity-100 group-hover:opacity-100"
9987
+ onClick={() => void createCard()}
11177
9988
  >
11178
- <label className="flex h-7 min-w-0 items-center gap-1.5 px-1 text-xs text-muted-foreground">
11179
- {isPending ? (
11180
- <Spinner className="size-3.5 shrink-0" />
11181
- ) : (
11182
- <IconPlus className="size-3.5 shrink-0" />
11183
- )}
11184
- <input
11185
- ref={inputRef}
11186
- value={title}
11187
- disabled={disabled}
11188
- aria-label={`New ${dateKey} timeline card title`}
11189
- placeholder={dbText("newPage")}
11190
- onChange={(event) => setTitle(event.target.value)}
11191
- onKeyDown={(event) => {
11192
- if (event.key === "Enter") {
11193
- event.preventDefault();
11194
- void submitNewCard();
11195
- }
11196
- if (event.key === "Escape") {
11197
- setTitle("");
11198
- event.currentTarget.blur();
11199
- }
11200
- }}
11201
- className="h-6 min-w-0 flex-1 bg-transparent outline-none placeholder:text-muted-foreground focus:placeholder:text-muted-foreground/70"
11202
- />
11203
- </label>
11204
- </form>
9989
+ {isPending ? (
9990
+ <Spinner className="size-3.5" />
9991
+ ) : (
9992
+ <IconPlus className="size-3.5" />
9993
+ )}
9994
+ </button>
11205
9995
  );
11206
9996
  }
11207
9997
 
@@ -12987,7 +11777,7 @@ function databaseBoardGroupingProperty(
12987
11777
  );
12988
11778
  }
12989
11779
 
12990
- function databaseViewGroupingProperty(
11780
+ export function databaseViewGroupingProperty(
12991
11781
  view: Pick<ContentDatabaseView, "groupByPropertyId" | "type">,
12992
11782
  properties: DocumentProperty[],
12993
11783
  ) {
@@ -13102,7 +11892,7 @@ export function databaseTimelineDays(anchorDate: Date) {
13102
11892
  return databaseCalendarMonthDays(anchorDate);
13103
11893
  }
13104
11894
 
13105
- function databaseTimelineEndDateProperty(
11895
+ export function databaseTimelineEndDateProperty(
13106
11896
  view: Pick<ContentDatabaseView, "endDatePropertyId">,
13107
11897
  properties: DocumentProperty[],
13108
11898
  startPropertyId?: string | null,
@@ -13342,7 +12132,7 @@ export function databaseBulkMultiSelectFilteredOptions(
13342
12132
  );
13343
12133
  }
13344
12134
 
13345
- function databaseTimelineRangeLabel(days: Date[]) {
12135
+ export function databaseTimelineRangeLabel(days: Date[]) {
13346
12136
  const first = days[0] ?? new Date();
13347
12137
  const last = days[days.length - 1] ?? first;
13348
12138
  const sameYear = first.getFullYear() === last.getFullYear();
@@ -13475,7 +12265,7 @@ export function databaseItemsWithoutDateValue(
13475
12265
  });
13476
12266
  }
13477
12267
 
13478
- function startOfMonth(date: Date) {
12268
+ export function startOfMonth(date: Date) {
13479
12269
  return new Date(date.getFullYear(), date.getMonth(), 1);
13480
12270
  }
13481
12271
 
@@ -17233,7 +16023,7 @@ function DatabaseTableRow({
17233
16023
  );
17234
16024
  }
17235
16025
 
17236
- function RowActionsCell({
16026
+ export function RowActionsCell({
17237
16027
  item,
17238
16028
  databaseDocumentId,
17239
16029
  onPreviewItem,