@allbluecn/web-app 0.6.3 → 0.7.1

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 (949) hide show
  1. package/package.json +26 -180
  2. package/src/__tests__/components/reference-inline.test.tsx +1 -1
  3. package/src/__tests__/setup.ts +1 -1
  4. package/src/__tests__/tag-badge.test.tsx +1 -1
  5. package/src/components/agents/schemas/agent-form.ts +1 -1
  6. package/src/components/animated-icons/layout-panel-top.tsx +1 -1
  7. package/src/components/auth/auth-layout.tsx +1 -1
  8. package/src/components/billing/__tests__/use-resource.test.tsx +1 -1
  9. package/src/components/billing/checkout-redirect.ts +1 -1
  10. package/src/components/billing/feature-gate.tsx +1 -1
  11. package/src/components/billing/subscription-provider.tsx +2 -2
  12. package/src/components/billing/use-feature.ts +1 -1
  13. package/src/components/billing/use-resource.ts +1 -1
  14. package/src/components/changelog/changelog-page.tsx +1 -1
  15. package/src/components/chat/ai-chat-history/utils/group-conversations.ts +1 -1
  16. package/src/components/chat/ai-citations/utils.ts +1 -1
  17. package/src/components/command/command-palette.tsx +1 -1
  18. package/src/components/forms/hooks/use-form-submit.ts +1 -1
  19. package/src/components/forms/schemas/common.ts +1 -1
  20. package/src/components/knowledge/editor/doc-header.tsx +4 -4
  21. package/src/components/knowledge/editor/knowledge-doc-editor.tsx +1 -1
  22. package/src/components/knowledge-public/knowledge-card.tsx +2 -2
  23. package/src/components/knowledge-public/knowledge-form-dialog.tsx +1 -1
  24. package/src/components/knowledge-public/sharers-avatar-group.tsx +1 -1
  25. package/src/components/layout/sidebar-03/__tests__/nav-workspace.test.tsx +1 -1
  26. package/src/components/layout/sidebar-03/nav-main.tsx +1 -1
  27. package/src/components/layout/sidebar-03/nav-notifications.tsx +1 -1
  28. package/src/components/layout/sidebar-03/user-menu.tsx +2 -2
  29. package/src/components/magicui/animated-theme-toggler.tsx +1 -1
  30. package/src/components/magicui/grid-pattern.tsx +1 -1
  31. package/src/components/mindmap/mindmap-doc-editor.tsx +4 -4
  32. package/src/components/notifications/settings-notifications.tsx +2 -2
  33. package/src/components/notifications/team-notifications.tsx +1 -1
  34. package/src/components/project/invite-member-dialog.tsx +1 -1
  35. package/src/components/project/project-activity-list.tsx +2 -2
  36. package/src/components/project/project-member-manager.tsx +1 -1
  37. package/src/components/project/schemas/create-project.ts +1 -1
  38. package/src/components/prototype/block/index.ts +22 -0
  39. package/src/components/prototype/component/Button.tsx +49 -0
  40. package/src/components/prototype/component/Card.tsx +49 -0
  41. package/src/components/prototype/component/GenericPrototype.tsx +42 -0
  42. package/src/components/prototype/component/Image.tsx +51 -0
  43. package/src/components/prototype/component/Input.tsx +45 -0
  44. package/src/components/prototype/component/Text.tsx +43 -0
  45. package/src/components/prototype/component/index.ts +102 -0
  46. package/src/components/prototype/component-preview.tsx +137 -0
  47. package/src/components/prototype/imported/.gitkeep +0 -0
  48. package/src/components/prototype/imported-registry.ts +25 -0
  49. package/src/components/prototype/index.ts +42 -0
  50. package/src/components/prototype/registry.ts +40 -0
  51. package/src/components/prototype/template/index.ts +22 -0
  52. package/src/components/prototype/types.ts +96 -0
  53. package/src/components/prototype/utils.ts +20 -0
  54. package/src/components/prototype/vite-env.d.ts +6 -0
  55. package/src/components/settings/language-selector.tsx +1 -1
  56. package/src/components/settings/personal-team/account/avatar/notion-avatar.tsx +2 -2
  57. package/src/components/settings/personal-team/team/team-member-list.tsx +1 -1
  58. package/src/components/share/prd/prd-share-client.tsx +1 -1
  59. package/src/components/share/prd/share-annotation-overlay.tsx +1 -1
  60. package/src/components/share/prd/share-comment-panel.tsx +1 -1
  61. package/src/components/share/prd/share-comment-review-panel.tsx +1 -1
  62. package/src/components/share/prd/share-directory-tree.tsx +1 -1
  63. package/src/components/share/prd/share-doc-view.tsx +1 -1
  64. package/src/components/share/prd/share-layout.tsx +1 -1
  65. package/src/components/share/prd/share-nav-bar.tsx +1 -1
  66. package/src/components/share/prd/share-password-gate.tsx +1 -1
  67. package/src/components/share/prd/share-prototype-view.tsx +1 -1
  68. package/src/components/share/prd/share-review-panel.tsx +1 -1
  69. package/src/components/share/prd/share-sse-listener.tsx +1 -1
  70. package/src/components/share/prd/share-theme-toggle.tsx +1 -1
  71. package/src/components/share/prd/version-share-client.tsx +1 -1
  72. package/src/components/shared/component-preview.tsx +1 -1
  73. package/src/components/shared/language-switcher.tsx +1 -1
  74. package/src/components/shared/name-confirm-dialog.tsx +1 -1
  75. package/src/components/shared/nav-float-button.tsx +1 -1
  76. package/src/components/shared/placeholder-page.tsx +1 -1
  77. package/src/components/story/columns.tsx +1 -1
  78. package/src/components/story/create-story-dialog.tsx +2 -2
  79. package/src/components/story/detail/__tests__/activity-timeline.test.tsx +1 -1
  80. package/src/components/story/detail/activity-timeline.tsx +1 -1
  81. package/src/components/story/detail/comment-item.tsx +1 -1
  82. package/src/components/story/detail/story-detail-body.tsx +2 -2
  83. package/src/components/story/display/__tests__/display-dropdown.test.tsx +1 -1
  84. package/src/components/story/display/group-resolver.tsx +1 -1
  85. package/src/components/story/filters/applied-filters.tsx +1 -1
  86. package/src/components/story/infinite-scroll-sentinel.tsx +1 -1
  87. package/src/components/story/inline-editors/assignee-editor.tsx +1 -1
  88. package/src/components/story/schemas/story-create.ts +1 -1
  89. package/src/components/story/views/kanban-card.tsx +1 -1
  90. package/src/components/story/views/view-types.ts +1 -1
  91. package/src/components/tiptap/__tests__/ai-extension.test.ts +120 -0
  92. package/src/components/tiptap/extension/ai-extension.ts +408 -0
  93. package/src/components/tiptap/extension/code-block-ellipsis-input-extension.ts +32 -0
  94. package/src/components/tiptap/extension/fullwidth-blockquote-extension.ts +31 -0
  95. package/src/components/tiptap/extension/indent-extension.ts +500 -0
  96. package/src/components/tiptap/extension/list-normalization-extension.ts +129 -0
  97. package/src/components/tiptap/extension/node-alignment-extension.ts +302 -0
  98. package/src/components/tiptap/extension/node-background-extension.ts +167 -0
  99. package/src/components/tiptap/extension/triple-click-block-selection-extension.ts +66 -0
  100. package/src/components/tiptap/extension/ui-state-extension.ts +114 -0
  101. package/src/components/tiptap/extensions/local-file/insert-local-file.ts +35 -0
  102. package/src/components/tiptap/extensions/local-file/local-file-node.ts +67 -0
  103. package/src/components/tiptap/global.d.ts +12 -0
  104. package/src/components/tiptap/hooks/use-composed-ref.ts +63 -0
  105. package/src/components/tiptap/hooks/use-cursor-visibility.ts +87 -0
  106. package/src/components/tiptap/hooks/use-element-rect.ts +179 -0
  107. package/src/components/tiptap/hooks/use-floating-element.ts +144 -0
  108. package/src/components/tiptap/hooks/use-floating-toolbar-visibility.ts +140 -0
  109. package/src/components/tiptap/hooks/use-is-breakpoint.ts +53 -0
  110. package/src/components/tiptap/hooks/use-isomorphic-layout-effect.ts +27 -0
  111. package/src/components/tiptap/hooks/use-menu-navigation.ts +212 -0
  112. package/src/components/tiptap/hooks/use-on-click-outside.ts +167 -0
  113. package/src/components/tiptap/hooks/use-tiptap-editor.ts +87 -0
  114. package/src/components/tiptap/hooks/use-ui-editor-state.ts +47 -0
  115. package/src/components/tiptap/hooks/use-window-size.ts +108 -0
  116. package/src/components/tiptap/icons/add-col-left-icon.tsx +47 -0
  117. package/src/components/tiptap/icons/add-col-right-icon.tsx +47 -0
  118. package/src/components/tiptap/icons/add-row-bottom-icon.tsx +47 -0
  119. package/src/components/tiptap/icons/add-row-top-icon.tsx +47 -0
  120. package/src/components/tiptap/icons/ai-sparkles-icon.tsx +49 -0
  121. package/src/components/tiptap/icons/align-bottom-icon.tsx +45 -0
  122. package/src/components/tiptap/icons/align-center-icon.tsx +55 -0
  123. package/src/components/tiptap/icons/align-center-vertical-icon.tsx +51 -0
  124. package/src/components/tiptap/icons/align-end-vertical-icon.tsx +51 -0
  125. package/src/components/tiptap/icons/align-justify-icon.tsx +55 -0
  126. package/src/components/tiptap/icons/align-left-icon.tsx +55 -0
  127. package/src/components/tiptap/icons/align-middle-icon.tsx +72 -0
  128. package/src/components/tiptap/icons/align-right-icon.tsx +55 -0
  129. package/src/components/tiptap/icons/align-start-vertical-icon.tsx +49 -0
  130. package/src/components/tiptap/icons/align-top-icon.tsx +45 -0
  131. package/src/components/tiptap/icons/alignment-icon.tsx +89 -0
  132. package/src/components/tiptap/icons/arrow-down-a-z-icon.tsx +51 -0
  133. package/src/components/tiptap/icons/arrow-down-icon.tsx +41 -0
  134. package/src/components/tiptap/icons/arrow-down-to-line-icon.tsx +45 -0
  135. package/src/components/tiptap/icons/arrow-down-z-a-icon.tsx +51 -0
  136. package/src/components/tiptap/icons/arrow-left-icon.tsx +41 -0
  137. package/src/components/tiptap/icons/arrow-right-icon.tsx +43 -0
  138. package/src/components/tiptap/icons/arrow-up-icon.tsx +43 -0
  139. package/src/components/tiptap/icons/at-sign-icon.tsx +43 -0
  140. package/src/components/tiptap/icons/ban-icon.tsx +43 -0
  141. package/src/components/tiptap/icons/blockquote-icon.tsx +61 -0
  142. package/src/components/tiptap/icons/bold-icon.tsx +43 -0
  143. package/src/components/tiptap/icons/check-ai-icon.tsx +49 -0
  144. package/src/components/tiptap/icons/check-icon.tsx +43 -0
  145. package/src/components/tiptap/icons/chevron-down-icon.tsx +43 -0
  146. package/src/components/tiptap/icons/chevron-right-icon.tsx +43 -0
  147. package/src/components/tiptap/icons/clipboard-icon.tsx +41 -0
  148. package/src/components/tiptap/icons/close-icon.tsx +41 -0
  149. package/src/components/tiptap/icons/code-block-icon.tsx +55 -0
  150. package/src/components/tiptap/icons/code2-icon.tsx +49 -0
  151. package/src/components/tiptap/icons/complete-sentence-icon.tsx +61 -0
  152. package/src/components/tiptap/icons/copy-icon.tsx +49 -0
  153. package/src/components/tiptap/icons/corner-down-left-icon.tsx +43 -0
  154. package/src/components/tiptap/icons/external-link-icon.tsx +45 -0
  155. package/src/components/tiptap/icons/grip-4-icon.tsx +41 -0
  156. package/src/components/tiptap/icons/grip-vertical-icon.tsx +61 -0
  157. package/src/components/tiptap/icons/heading-five-icon.tsx +45 -0
  158. package/src/components/tiptap/icons/heading-four-icon.tsx +45 -0
  159. package/src/components/tiptap/icons/heading-one-icon.tsx +45 -0
  160. package/src/components/tiptap/icons/heading-six-icon.tsx +47 -0
  161. package/src/components/tiptap/icons/heading-three-icon.tsx +53 -0
  162. package/src/components/tiptap/icons/heading-two-icon.tsx +45 -0
  163. package/src/components/tiptap/icons/highlighter-icon.tsx +43 -0
  164. package/src/components/tiptap/icons/image-caption-icon.tsx +55 -0
  165. package/src/components/tiptap/icons/image-icon.tsx +43 -0
  166. package/src/components/tiptap/icons/image-plus-icon.tsx +43 -0
  167. package/src/components/tiptap/icons/indent-decrease-icon.tsx +57 -0
  168. package/src/components/tiptap/icons/indent-increase-icon.tsx +57 -0
  169. package/src/components/tiptap/icons/italic-icon.tsx +41 -0
  170. package/src/components/tiptap/icons/languages-icon.tsx +51 -0
  171. package/src/components/tiptap/icons/link-icon.tsx +45 -0
  172. package/src/components/tiptap/icons/list-icon.tsx +73 -0
  173. package/src/components/tiptap/icons/list-indented-icon.tsx +73 -0
  174. package/src/components/tiptap/icons/list-ordered-icon.tsx +73 -0
  175. package/src/components/tiptap/icons/list-todo-icon.tsx +67 -0
  176. package/src/components/tiptap/icons/message-square-icon.tsx +43 -0
  177. package/src/components/tiptap/icons/message-square-plus-icon.tsx +49 -0
  178. package/src/components/tiptap/icons/mic-ai-icon.tsx +51 -0
  179. package/src/components/tiptap/icons/minus-icon.tsx +43 -0
  180. package/src/components/tiptap/icons/moon-star-icon.tsx +47 -0
  181. package/src/components/tiptap/icons/more-vertical-icon.tsx +55 -0
  182. package/src/components/tiptap/icons/move-horizontal-icon.tsx +41 -0
  183. package/src/components/tiptap/icons/network-icon.tsx +48 -0
  184. package/src/components/tiptap/icons/paint-bucket-icon.tsx +49 -0
  185. package/src/components/tiptap/icons/plus-icon.tsx +41 -0
  186. package/src/components/tiptap/icons/plus-small-icon.tsx +41 -0
  187. package/src/components/tiptap/icons/redo2-icon.tsx +43 -0
  188. package/src/components/tiptap/icons/refresh-ai-icon.tsx +51 -0
  189. package/src/components/tiptap/icons/refresh-ccw-icon.tsx +45 -0
  190. package/src/components/tiptap/icons/repeat-2-icon.tsx +43 -0
  191. package/src/components/tiptap/icons/rotate-ccw-icon.tsx +41 -0
  192. package/src/components/tiptap/icons/simplify-2-icon.tsx +41 -0
  193. package/src/components/tiptap/icons/smile-ai-icon.tsx +55 -0
  194. package/src/components/tiptap/icons/smile-plus-icon.tsx +43 -0
  195. package/src/components/tiptap/icons/square-x-icon.tsx +43 -0
  196. package/src/components/tiptap/icons/stop-circle-2-icon.tsx +43 -0
  197. package/src/components/tiptap/icons/strike-icon.tsx +45 -0
  198. package/src/components/tiptap/icons/subscript-icon.tsx +55 -0
  199. package/src/components/tiptap/icons/summarize-text-icon.tsx +53 -0
  200. package/src/components/tiptap/icons/sun-icon.tsx +75 -0
  201. package/src/components/tiptap/icons/superscript-icon.tsx +55 -0
  202. package/src/components/tiptap/icons/table-cell-merge-icon.tsx +61 -0
  203. package/src/components/tiptap/icons/table-cell-split-icon.tsx +61 -0
  204. package/src/components/tiptap/icons/table-column-icon.tsx +43 -0
  205. package/src/components/tiptap/icons/table-header-column-icon.tsx +45 -0
  206. package/src/components/tiptap/icons/table-header-row-icon.tsx +43 -0
  207. package/src/components/tiptap/icons/table-icon.tsx +43 -0
  208. package/src/components/tiptap/icons/table-row-icon.tsx +43 -0
  209. package/src/components/tiptap/icons/text-color-small-icon.tsx +43 -0
  210. package/src/components/tiptap/icons/text-extend-icon.tsx +53 -0
  211. package/src/components/tiptap/icons/text-reduce-icon.tsx +49 -0
  212. package/src/components/tiptap/icons/trash-icon.tsx +43 -0
  213. package/src/components/tiptap/icons/type-icon.tsx +41 -0
  214. package/src/components/tiptap/icons/underline-icon.tsx +43 -0
  215. package/src/components/tiptap/icons/undo2-icon.tsx +43 -0
  216. package/src/components/tiptap/icons/x-icon.tsx +41 -0
  217. package/src/components/tiptap/index.ts +1 -0
  218. package/src/components/tiptap/lib/advanced-utils.ts +388 -0
  219. package/src/components/tiptap/lib/ai-types.ts +41 -0
  220. package/src/components/tiptap/lib/collab-utils.ts +147 -0
  221. package/src/components/tiptap/lib/datetime.ts +1 -0
  222. package/src/components/tiptap/lib/fullwidth.ts +44 -0
  223. package/src/components/tiptap/lib/pacer.ts +95 -0
  224. package/src/components/tiptap/lib/utils/attr.ts +67 -0
  225. package/src/components/tiptap/lib/utils/constants.ts +46 -0
  226. package/src/components/tiptap/lib/utils/math.ts +23 -0
  227. package/src/components/tiptap/lib/utils/node.ts +136 -0
  228. package/src/components/tiptap/lib/utils/platform.ts +77 -0
  229. package/src/components/tiptap/lib/utils/schema.ts +75 -0
  230. package/src/components/tiptap/lib/utils/selection.ts +218 -0
  231. package/src/components/tiptap/lib/utils/url.ts +122 -0
  232. package/src/components/tiptap/lib/utils.ts +57 -0
  233. package/src/components/tiptap/mindmap/lib/__tests__/default-mindmap-data.test.ts +58 -0
  234. package/src/components/tiptap/mindmap/lib/default-mindmap-data.ts +36 -0
  235. package/src/components/tiptap/mindmap/mind-map.tsx +579 -0
  236. package/src/components/tiptap/mindmap/mindmap-fullscreen-dialog.tsx +52 -0
  237. package/src/components/tiptap/node/annotation-node/annotation-extension.ts +47 -0
  238. package/src/components/tiptap/node/annotation-node/annotation-node-view.tsx +185 -0
  239. package/src/components/tiptap/node/annotation-node/annotation-node.scss +77 -0
  240. package/src/components/tiptap/node/annotation-node/index.ts +2 -0
  241. package/src/components/tiptap/node/blockquote-node/blockquote-node.scss +37 -0
  242. package/src/components/tiptap/node/code-block-node/code-block-node.scss +54 -0
  243. package/src/components/tiptap/node/doc-card-extension.tsx +226 -0
  244. package/src/components/tiptap/node/heading-node/heading-node.scss +45 -0
  245. package/src/components/tiptap/node/horizontal-rule-node/horizontal-rule-node-extension.ts +31 -0
  246. package/src/components/tiptap/node/horizontal-rule-node/horizontal-rule-node.scss +25 -0
  247. package/src/components/tiptap/node/image-node/image-node-extension.ts +253 -0
  248. package/src/components/tiptap/node/image-node/image-node-floating.tsx +65 -0
  249. package/src/components/tiptap/node/image-node/image-node-view.scss +95 -0
  250. package/src/components/tiptap/node/image-node/image-node-view.tsx +363 -0
  251. package/src/components/tiptap/node/image-node/image-node.scss +35 -0
  252. package/src/components/tiptap/node/image-upload-node/image-upload-node-extension.ts +179 -0
  253. package/src/components/tiptap/node/image-upload-node/image-upload-node.scss +249 -0
  254. package/src/components/tiptap/node/image-upload-node/image-upload-node.tsx +570 -0
  255. package/src/components/tiptap/node/image-upload-node/index.tsx +18 -0
  256. package/src/components/tiptap/node/inline-node-selection.ts +42 -0
  257. package/src/components/tiptap/node/list-node/list-node.scss +208 -0
  258. package/src/components/tiptap/node/mention-extension.ts +163 -0
  259. package/src/components/tiptap/node/mindmap-node/mindmap-extension.ts +87 -0
  260. package/src/components/tiptap/node/mindmap-node/mindmap-node-view.tsx +61 -0
  261. package/src/components/tiptap/node/paragraph-node/paragraph-node.scss +1 -0
  262. package/src/components/tiptap/node/table-node/extensions/table-handle/helpers/create-image.ts +303 -0
  263. package/src/components/tiptap/node/table-node/extensions/table-handle/index.ts +19 -0
  264. package/src/components/tiptap/node/table-node/extensions/table-handle/table-handle-plugin.ts +863 -0
  265. package/src/components/tiptap/node/table-node/extensions/table-handle/table-handle.ts +67 -0
  266. package/src/components/tiptap/node/table-node/extensions/table-node-extension.ts +264 -0
  267. package/src/components/tiptap/node/table-node/hooks/use-table-handle-state.ts +88 -0
  268. package/src/components/tiptap/node/table-node/lib/tiptap-table-utils.ts +1306 -0
  269. package/src/components/tiptap/node/table-node/styles/prosemirror-table.scss +48 -0
  270. package/src/components/tiptap/node/table-node/styles/table-node.scss +211 -0
  271. package/src/components/tiptap/node/table-node/ui/table-add-row-column-button/index.tsx +19 -0
  272. package/src/components/tiptap/node/table-node/ui/table-add-row-column-button/table-add-row-column-button.tsx +117 -0
  273. package/src/components/tiptap/node/table-node/ui/table-add-row-column-button/use-table-add-row-column.ts +365 -0
  274. package/src/components/tiptap/node/table-node/ui/table-align-cell-button/index.tsx +19 -0
  275. package/src/components/tiptap/node/table-node/ui/table-align-cell-button/table-align-cell-button.tsx +144 -0
  276. package/src/components/tiptap/node/table-node/ui/table-align-cell-button/use-table-align-cell.ts +565 -0
  277. package/src/components/tiptap/node/table-node/ui/table-alignment-menu/index.tsx +18 -0
  278. package/src/components/tiptap/node/table-node/ui/table-alignment-menu/table-alignment-menu.tsx +177 -0
  279. package/src/components/tiptap/node/table-node/ui/table-cell-handle-menu/index.tsx +18 -0
  280. package/src/components/tiptap/node/table-node/ui/table-cell-handle-menu/table-cell-handle-menu.scss +121 -0
  281. package/src/components/tiptap/node/table-node/ui/table-cell-handle-menu/table-cell-handle-menu.tsx +227 -0
  282. package/src/components/tiptap/node/table-node/ui/table-clear-row-column-content-button/index.tsx +19 -0
  283. package/src/components/tiptap/node/table-node/ui/table-clear-row-column-content-button/table-clear-row-column-content-button.tsx +116 -0
  284. package/src/components/tiptap/node/table-node/ui/table-clear-row-column-content-button/use-table-clear-row-column-content.ts +487 -0
  285. package/src/components/tiptap/node/table-node/ui/table-delete-row-column-button/index.tsx +19 -0
  286. package/src/components/tiptap/node/table-node/ui/table-delete-row-column-button/table-delete-row-column-button.tsx +115 -0
  287. package/src/components/tiptap/node/table-node/ui/table-delete-row-column-button/use-table-delete-row-column.ts +283 -0
  288. package/src/components/tiptap/node/table-node/ui/table-duplicate-row-column-button/index.tsx +19 -0
  289. package/src/components/tiptap/node/table-node/ui/table-duplicate-row-column-button/table-duplicate-row-column-button.tsx +107 -0
  290. package/src/components/tiptap/node/table-node/ui/table-duplicate-row-column-button/use-table-duplicate-row-column.ts +424 -0
  291. package/src/components/tiptap/node/table-node/ui/table-extend-row-column-button/index.tsx +19 -0
  292. package/src/components/tiptap/node/table-node/ui/table-extend-row-column-button/table-extend-row-column-button.scss +36 -0
  293. package/src/components/tiptap/node/table-node/ui/table-extend-row-column-button/table-extend-row-column-button.tsx +272 -0
  294. package/src/components/tiptap/node/table-node/ui/table-extend-row-column-button/use-table-extend-row-column.ts +135 -0
  295. package/src/components/tiptap/node/table-node/ui/table-fit-to-width-button/index.tsx +19 -0
  296. package/src/components/tiptap/node/table-node/ui/table-fit-to-width-button/table-fit-to-width-button.tsx +113 -0
  297. package/src/components/tiptap/node/table-node/ui/table-fit-to-width-button/use-table-fit-to-width.ts +259 -0
  298. package/src/components/tiptap/node/table-node/ui/table-handle/index.tsx +19 -0
  299. package/src/components/tiptap/node/table-node/ui/table-handle/table-handle.tsx +179 -0
  300. package/src/components/tiptap/node/table-node/ui/table-handle/use-table-handle-positioning.ts +272 -0
  301. package/src/components/tiptap/node/table-node/ui/table-handle-menu/index.tsx +18 -0
  302. package/src/components/tiptap/node/table-node/ui/table-handle-menu/table-handle-menu.scss +54 -0
  303. package/src/components/tiptap/node/table-node/ui/table-handle-menu/table-handle-menu.tsx +765 -0
  304. package/src/components/tiptap/node/table-node/ui/table-header-row-column-button/index.tsx +19 -0
  305. package/src/components/tiptap/node/table-node/ui/table-header-row-column-button/table-header-row-column-button.tsx +114 -0
  306. package/src/components/tiptap/node/table-node/ui/table-header-row-column-button/use-table-header-row-column.ts +280 -0
  307. package/src/components/tiptap/node/table-node/ui/table-merge-split-cell-button/index.tsx +19 -0
  308. package/src/components/tiptap/node/table-node/ui/table-merge-split-cell-button/table-merge-split-cell-button.tsx +140 -0
  309. package/src/components/tiptap/node/table-node/ui/table-merge-split-cell-button/use-table-merge-split-cell.ts +305 -0
  310. package/src/components/tiptap/node/table-node/ui/table-move-row-column-button/index.tsx +19 -0
  311. package/src/components/tiptap/node/table-node/ui/table-move-row-column-button/table-move-row-column-button.tsx +138 -0
  312. package/src/components/tiptap/node/table-node/ui/table-move-row-column-button/use-table-move-row-column.ts +498 -0
  313. package/src/components/tiptap/node/table-node/ui/table-selection-overlay/index.tsx +18 -0
  314. package/src/components/tiptap/node/table-node/ui/table-selection-overlay/table-selection-overlay.tsx +590 -0
  315. package/src/components/tiptap/node/table-node/ui/table-selection-overlay/use-resize-overlay.ts +94 -0
  316. package/src/components/tiptap/node/table-node/ui/table-sort-row-column-button/index.tsx +19 -0
  317. package/src/components/tiptap/node/table-node/ui/table-sort-row-column-button/table-sort-row-column-button.tsx +115 -0
  318. package/src/components/tiptap/node/table-node/ui/table-sort-row-column-button/use-table-sort-row-column.ts +495 -0
  319. package/src/components/tiptap/node/table-node/ui/table-trigger-button/index.tsx +20 -0
  320. package/src/components/tiptap/node/table-node/ui/table-trigger-button/table-grid-selector.scss +98 -0
  321. package/src/components/tiptap/node/table-node/ui/table-trigger-button/table-grid-selector.tsx +236 -0
  322. package/src/components/tiptap/node/table-node/ui/table-trigger-button/table-trigger-button.tsx +147 -0
  323. package/src/components/tiptap/node/table-node/ui/table-trigger-button/use-table-trigger.ts +196 -0
  324. package/src/components/tiptap/node/toc-node/context/toc-context.tsx +214 -0
  325. package/src/components/tiptap/node/toc-node/extensions/toc-node-extension.ts +172 -0
  326. package/src/components/tiptap/node/toc-node/index.ts +20 -0
  327. package/src/components/tiptap/node/toc-node/toc-node.scss +105 -0
  328. package/src/components/tiptap/node/toc-node/toc-node.tsx +131 -0
  329. package/src/components/tiptap/node/toc-node/ui/toc-show-title-button/index.tsx +19 -0
  330. package/src/components/tiptap/node/toc-node/ui/toc-show-title-button/toc-show-title-button.tsx +113 -0
  331. package/src/components/tiptap/node/toc-node/ui/toc-show-title-button/toc-show-title.ts +228 -0
  332. package/src/components/tiptap/node/toc-node/ui/toc-sidebar/index.tsx +18 -0
  333. package/src/components/tiptap/node/toc-node/ui/toc-sidebar/toc-sidebar.scss +265 -0
  334. package/src/components/tiptap/node/toc-node/ui/toc-sidebar/toc-sidebar.tsx +272 -0
  335. package/src/components/tiptap/notion-like/data/content.json +1658 -0
  336. package/src/components/tiptap/notion-like/index.ts +2 -0
  337. package/src/components/tiptap/notion-like/notion-like-editor-header.scss +29 -0
  338. package/src/components/tiptap/notion-like/notion-like-editor-header.tsx +91 -0
  339. package/src/components/tiptap/notion-like/notion-like-editor-mobile-toolbar.tsx +704 -0
  340. package/src/components/tiptap/notion-like/notion-like-editor-theme-toggle.tsx +66 -0
  341. package/src/components/tiptap/notion-like/notion-like-editor-toolbar-floating.tsx +435 -0
  342. package/src/components/tiptap/notion-like/notion-like-editor.scss +181 -0
  343. package/src/components/tiptap/notion-like/notion-like-editor.tsx +589 -0
  344. package/src/components/tiptap/notion-like/setup-error-message/index.tsx +19 -0
  345. package/src/components/tiptap/notion-like/setup-error-message/setup-error-message.scss +108 -0
  346. package/src/components/tiptap/notion-like/setup-error-message/setup-error-message.tsx +116 -0
  347. package/src/components/tiptap/ui/ai-ask-button/ai-ask-button.tsx +124 -0
  348. package/src/components/tiptap/ui/ai-ask-button/index.tsx +19 -0
  349. package/src/components/tiptap/ui/ai-ask-button/use-ai-ask.ts +192 -0
  350. package/src/components/tiptap/ui/ai-menu/ai-menu-actions/ai-menu-actions.scss +11 -0
  351. package/src/components/tiptap/ui/ai-menu/ai-menu-actions/ai-menu-actions.tsx +103 -0
  352. package/src/components/tiptap/ui/ai-menu/ai-menu-actions/index.tsx +18 -0
  353. package/src/components/tiptap/ui/ai-menu/ai-menu-hooks.ts +325 -0
  354. package/src/components/tiptap/ui/ai-menu/ai-menu-input/ai-menu-input-hooks.ts +61 -0
  355. package/src/components/tiptap/ui/ai-menu/ai-menu-input/ai-menu-input-types.ts +32 -0
  356. package/src/components/tiptap/ui/ai-menu/ai-menu-input/ai-menu-input.scss +114 -0
  357. package/src/components/tiptap/ui/ai-menu/ai-menu-input/ai-menu-input.tsx +269 -0
  358. package/src/components/tiptap/ui/ai-menu/ai-menu-input/index.tsx +20 -0
  359. package/src/components/tiptap/ui/ai-menu/ai-menu-items/ai-menu-items-constants.ts +63 -0
  360. package/src/components/tiptap/ui/ai-menu/ai-menu-items/ai-menu-items-types.ts +64 -0
  361. package/src/components/tiptap/ui/ai-menu/ai-menu-items/ai-menu-items.tsx +381 -0
  362. package/src/components/tiptap/ui/ai-menu/ai-menu-items/index.tsx +20 -0
  363. package/src/components/tiptap/ui/ai-menu/ai-menu-items/language-selection-submenu.tsx +140 -0
  364. package/src/components/tiptap/ui/ai-menu/ai-menu-items/menu-action-renderer.tsx +105 -0
  365. package/src/components/tiptap/ui/ai-menu/ai-menu-items/tone-selection-submenu.tsx +125 -0
  366. package/src/components/tiptap/ui/ai-menu/ai-menu-types.ts +42 -0
  367. package/src/components/tiptap/ui/ai-menu/ai-menu-utils.ts +255 -0
  368. package/src/components/tiptap/ui/ai-menu/ai-menu.scss +101 -0
  369. package/src/components/tiptap/ui/ai-menu/ai-menu.tsx +427 -0
  370. package/src/components/tiptap/ui/ai-menu/index.tsx +25 -0
  371. package/src/components/tiptap/ui/blockquote-button/blockquote-button.tsx +143 -0
  372. package/src/components/tiptap/ui/blockquote-button/index.tsx +19 -0
  373. package/src/components/tiptap/ui/blockquote-button/use-blockquote.ts +290 -0
  374. package/src/components/tiptap/ui/code-block-button/code-block-button.tsx +143 -0
  375. package/src/components/tiptap/ui/code-block-button/index.tsx +19 -0
  376. package/src/components/tiptap/ui/code-block-button/use-code-block.ts +300 -0
  377. package/src/components/tiptap/ui/color-highlight-button/color-highlight-button.scss +49 -0
  378. package/src/components/tiptap/ui/color-highlight-button/color-highlight-button.tsx +188 -0
  379. package/src/components/tiptap/ui/color-highlight-button/index.tsx +19 -0
  380. package/src/components/tiptap/ui/color-highlight-button/use-color-highlight.ts +397 -0
  381. package/src/components/tiptap/ui/color-highlight-popover/color-highlight-popover.tsx +251 -0
  382. package/src/components/tiptap/ui/color-highlight-popover/index.tsx +18 -0
  383. package/src/components/tiptap/ui/color-menu/color-menu.tsx +228 -0
  384. package/src/components/tiptap/ui/color-menu/index.tsx +18 -0
  385. package/src/components/tiptap/ui/color-text-button/color-text-button.scss +52 -0
  386. package/src/components/tiptap/ui/color-text-button/color-text-button.tsx +168 -0
  387. package/src/components/tiptap/ui/color-text-button/index.tsx +19 -0
  388. package/src/components/tiptap/ui/color-text-button/use-color-text.ts +303 -0
  389. package/src/components/tiptap/ui/color-text-popover/color-text-popover.scss +40 -0
  390. package/src/components/tiptap/ui/color-text-popover/color-text-popover.tsx +471 -0
  391. package/src/components/tiptap/ui/color-text-popover/index.tsx +19 -0
  392. package/src/components/tiptap/ui/color-text-popover/use-color-text-popover.ts +295 -0
  393. package/src/components/tiptap/ui/copy-anchor-link-button/copy-anchor-link-button.tsx +136 -0
  394. package/src/components/tiptap/ui/copy-anchor-link-button/index.tsx +20 -0
  395. package/src/components/tiptap/ui/copy-anchor-link-button/use-copy-anchor-link.ts +282 -0
  396. package/src/components/tiptap/ui/copy-anchor-link-button/use-scroll-to-hash.ts +155 -0
  397. package/src/components/tiptap/ui/copy-to-clipboard-button/copy-to-clipboard-button.tsx +134 -0
  398. package/src/components/tiptap/ui/copy-to-clipboard-button/index.tsx +19 -0
  399. package/src/components/tiptap/ui/copy-to-clipboard-button/use-copy-to-clipboard.ts +275 -0
  400. package/src/components/tiptap/ui/delete-node-button/delete-node-button.tsx +132 -0
  401. package/src/components/tiptap/ui/delete-node-button/index.tsx +19 -0
  402. package/src/components/tiptap/ui/delete-node-button/use-delete-node.ts +259 -0
  403. package/src/components/tiptap/ui/doc-reference-floating/doc-reference-floating.tsx +120 -0
  404. package/src/components/tiptap/ui/doc-reference-interaction/doc-reference-interaction.tsx +209 -0
  405. package/src/components/tiptap/ui/drag-context-menu/drag-context-menu-types.ts +47 -0
  406. package/src/components/tiptap/ui/drag-context-menu/drag-context-menu.scss +15 -0
  407. package/src/components/tiptap/ui/drag-context-menu/drag-context-menu.tsx +558 -0
  408. package/src/components/tiptap/ui/drag-context-menu/index.tsx +19 -0
  409. package/src/components/tiptap/ui/duplicate-button/duplicate-button.tsx +132 -0
  410. package/src/components/tiptap/ui/duplicate-button/index.tsx +19 -0
  411. package/src/components/tiptap/ui/duplicate-button/use-duplicate.ts +240 -0
  412. package/src/components/tiptap/ui/emoji-dropdown-menu/emoji-dropdown-menu.tsx +124 -0
  413. package/src/components/tiptap/ui/emoji-dropdown-menu/index.tsx +18 -0
  414. package/src/components/tiptap/ui/emoji-menu/emoji-menu-utils.ts +53 -0
  415. package/src/components/tiptap/ui/emoji-menu/emoji-menu.scss +28 -0
  416. package/src/components/tiptap/ui/emoji-menu/emoji-menu.tsx +166 -0
  417. package/src/components/tiptap/ui/emoji-menu/index.tsx +19 -0
  418. package/src/components/tiptap/ui/emoji-trigger-button/emoji-trigger-button.tsx +146 -0
  419. package/src/components/tiptap/ui/emoji-trigger-button/index.tsx +19 -0
  420. package/src/components/tiptap/ui/emoji-trigger-button/use-emoji-trigger.ts +338 -0
  421. package/src/components/tiptap/ui/heading-button/heading-button.tsx +142 -0
  422. package/src/components/tiptap/ui/heading-button/index.tsx +19 -0
  423. package/src/components/tiptap/ui/heading-button/use-heading.ts +374 -0
  424. package/src/components/tiptap/ui/image-align-button/image-align-button.tsx +154 -0
  425. package/src/components/tiptap/ui/image-align-button/index.tsx +19 -0
  426. package/src/components/tiptap/ui/image-align-button/use-image-align.ts +313 -0
  427. package/src/components/tiptap/ui/image-caption-button/image-caption-button.tsx +109 -0
  428. package/src/components/tiptap/ui/image-caption-button/index.tsx +19 -0
  429. package/src/components/tiptap/ui/image-caption-button/use-image-caption.ts +232 -0
  430. package/src/components/tiptap/ui/image-download-button/image-download-button.tsx +141 -0
  431. package/src/components/tiptap/ui/image-download-button/index.tsx +19 -0
  432. package/src/components/tiptap/ui/image-download-button/use-image-download.ts +384 -0
  433. package/src/components/tiptap/ui/image-upload-button/image-upload-button.tsx +148 -0
  434. package/src/components/tiptap/ui/image-upload-button/index.tsx +19 -0
  435. package/src/components/tiptap/ui/image-upload-button/use-image-upload.ts +214 -0
  436. package/src/components/tiptap/ui/improve-dropdown/improve-dropdown.tsx +311 -0
  437. package/src/components/tiptap/ui/improve-dropdown/index.tsx +19 -0
  438. package/src/components/tiptap/ui/improve-dropdown/use-improve-dropdown.ts +294 -0
  439. package/src/components/tiptap/ui/indent-button/indent-button.tsx +148 -0
  440. package/src/components/tiptap/ui/indent-button/index.tsx +19 -0
  441. package/src/components/tiptap/ui/indent-button/use-indent.ts +217 -0
  442. package/src/components/tiptap/ui/link-popover/index.tsx +19 -0
  443. package/src/components/tiptap/ui/link-popover/link-popover.scss +16 -0
  444. package/src/components/tiptap/ui/link-popover/link-popover.tsx +333 -0
  445. package/src/components/tiptap/ui/link-popover/use-link-popover.ts +316 -0
  446. package/src/components/tiptap/ui/list-button/index.tsx +19 -0
  447. package/src/components/tiptap/ui/list-button/list-button.tsx +138 -0
  448. package/src/components/tiptap/ui/list-button/use-list.ts +370 -0
  449. package/src/components/tiptap/ui/mark-button/index.tsx +19 -0
  450. package/src/components/tiptap/ui/mark-button/mark-button.tsx +138 -0
  451. package/src/components/tiptap/ui/mark-button/use-mark.ts +247 -0
  452. package/src/components/tiptap/ui/mention-dropdown-menu/index.tsx +18 -0
  453. package/src/components/tiptap/ui/mention-dropdown-menu/mention-dropdown-menu.tsx +194 -0
  454. package/src/components/tiptap/ui/mention-trigger-button/index.tsx +19 -0
  455. package/src/components/tiptap/ui/mention-trigger-button/mention-trigger-button.tsx +137 -0
  456. package/src/components/tiptap/ui/mention-trigger-button/use-mention-trigger.ts +362 -0
  457. package/src/components/tiptap/ui/move-node-button/index.tsx +19 -0
  458. package/src/components/tiptap/ui/move-node-button/move-node-button.tsx +138 -0
  459. package/src/components/tiptap/ui/move-node-button/use-move-node.ts +230 -0
  460. package/src/components/tiptap/ui/reference-dropdown-menu/index.tsx +18 -0
  461. package/src/components/tiptap/ui/reference-dropdown-menu/reference-dropdown-menu.tsx +231 -0
  462. package/src/components/tiptap/ui/reset-all-formatting-button/index.tsx +19 -0
  463. package/src/components/tiptap/ui/reset-all-formatting-button/reset-all-formatting-button.tsx +144 -0
  464. package/src/components/tiptap/ui/reset-all-formatting-button/use-reset-all-formatting.ts +279 -0
  465. package/src/components/tiptap/ui/slash-command-trigger-button/index.tsx +19 -0
  466. package/src/components/tiptap/ui/slash-command-trigger-button/slash-command-trigger-button.tsx +143 -0
  467. package/src/components/tiptap/ui/slash-command-trigger-button/use-slash-command-trigger.ts +305 -0
  468. package/src/components/tiptap/ui/slash-dropdown-menu/index.tsx +19 -0
  469. package/src/components/tiptap/ui/slash-dropdown-menu/slash-dropdown-menu.scss +33 -0
  470. package/src/components/tiptap/ui/slash-dropdown-menu/slash-dropdown-menu.tsx +222 -0
  471. package/src/components/tiptap/ui/slash-dropdown-menu/use-slash-dropdown-menu.ts +498 -0
  472. package/src/components/tiptap/ui/text-align-button/index.tsx +19 -0
  473. package/src/components/tiptap/ui/text-align-button/text-align-button.tsx +160 -0
  474. package/src/components/tiptap/ui/text-align-button/use-text-align.ts +248 -0
  475. package/src/components/tiptap/ui/text-button/index.tsx +19 -0
  476. package/src/components/tiptap/ui/text-button/text-button.tsx +135 -0
  477. package/src/components/tiptap/ui/text-button/use-text.ts +308 -0
  478. package/src/components/tiptap/ui/turn-into-dropdown/index.tsx +19 -0
  479. package/src/components/tiptap/ui/turn-into-dropdown/turn-into-dropdown.tsx +243 -0
  480. package/src/components/tiptap/ui/turn-into-dropdown/use-turn-into-dropdown.ts +294 -0
  481. package/src/components/tiptap/ui/undo-redo-button/index.tsx +19 -0
  482. package/src/components/tiptap/ui/undo-redo-button/undo-redo-button.tsx +141 -0
  483. package/src/components/tiptap/ui/undo-redo-button/use-undo-redo.ts +207 -0
  484. package/src/components/tiptap/ui-primitive/avatar/avatar.scss +118 -0
  485. package/src/components/tiptap/ui-primitive/avatar/avatar.tsx +255 -0
  486. package/src/components/tiptap/ui-primitive/avatar/index.tsx +18 -0
  487. package/src/components/tiptap/ui-primitive/badge/badge-colors.scss +395 -0
  488. package/src/components/tiptap/ui-primitive/badge/badge-group.scss +16 -0
  489. package/src/components/tiptap/ui-primitive/badge/badge.scss +99 -0
  490. package/src/components/tiptap/ui-primitive/badge/badge.tsx +62 -0
  491. package/src/components/tiptap/ui-primitive/badge/index.tsx +18 -0
  492. package/src/components/tiptap/ui-primitive/button/button-colors.scss +429 -0
  493. package/src/components/tiptap/ui-primitive/button/button.scss +314 -0
  494. package/src/components/tiptap/ui-primitive/button/button.tsx +119 -0
  495. package/src/components/tiptap/ui-primitive/button/index.tsx +18 -0
  496. package/src/components/tiptap/ui-primitive/button-group/button-group.scss +79 -0
  497. package/src/components/tiptap/ui-primitive/button-group/button-group.tsx +89 -0
  498. package/src/components/tiptap/ui-primitive/button-group/index.tsx +18 -0
  499. package/src/components/tiptap/ui-primitive/card/card.scss +74 -0
  500. package/src/components/tiptap/ui-primitive/card/card.tsx +95 -0
  501. package/src/components/tiptap/ui-primitive/card/index.tsx +18 -0
  502. package/src/components/tiptap/ui-primitive/combobox/combobox.scss +90 -0
  503. package/src/components/tiptap/ui-primitive/combobox/combobox.tsx +231 -0
  504. package/src/components/tiptap/ui-primitive/combobox/index.tsx +18 -0
  505. package/src/components/tiptap/ui-primitive/dropdown-menu/dropdown-menu.scss +152 -0
  506. package/src/components/tiptap/ui-primitive/dropdown-menu/dropdown-menu.tsx +280 -0
  507. package/src/components/tiptap/ui-primitive/dropdown-menu/index.tsx +18 -0
  508. package/src/components/tiptap/ui-primitive/input/index.tsx +18 -0
  509. package/src/components/tiptap/ui-primitive/input/input.scss +41 -0
  510. package/src/components/tiptap/ui-primitive/input/input.tsx +33 -0
  511. package/src/components/tiptap/ui-primitive/input-group/index.tsx +18 -0
  512. package/src/components/tiptap/ui-primitive/input-group/input-group.scss +225 -0
  513. package/src/components/tiptap/ui-primitive/input-group/input-group.tsx +152 -0
  514. package/src/components/tiptap/ui-primitive/label/index.tsx +18 -0
  515. package/src/components/tiptap/ui-primitive/label/label.scss +20 -0
  516. package/src/components/tiptap/ui-primitive/label/label.tsx +34 -0
  517. package/src/components/tiptap/ui-primitive/menu/index.tsx +22 -0
  518. package/src/components/tiptap/ui-primitive/menu/menu-context.ts +35 -0
  519. package/src/components/tiptap/ui-primitive/menu/menu-hooks.ts +118 -0
  520. package/src/components/tiptap/ui-primitive/menu/menu-types.ts +75 -0
  521. package/src/components/tiptap/ui-primitive/menu/menu-utils.ts +80 -0
  522. package/src/components/tiptap/ui-primitive/menu/menu.scss +68 -0
  523. package/src/components/tiptap/ui-primitive/menu/menu.tsx +327 -0
  524. package/src/components/tiptap/ui-primitive/popover/index.tsx +18 -0
  525. package/src/components/tiptap/ui-primitive/popover/popover.scss +64 -0
  526. package/src/components/tiptap/ui-primitive/popover/popover.tsx +53 -0
  527. package/src/components/tiptap/ui-primitive/separator/index.tsx +18 -0
  528. package/src/components/tiptap/ui-primitive/separator/separator.scss +23 -0
  529. package/src/components/tiptap/ui-primitive/separator/separator.tsx +46 -0
  530. package/src/components/tiptap/ui-primitive/sidebar/index.tsx +18 -0
  531. package/src/components/tiptap/ui-primitive/sidebar/sidebar.scss +389 -0
  532. package/src/components/tiptap/ui-primitive/sidebar/sidebar.tsx +633 -0
  533. package/src/components/tiptap/ui-primitive/spacer/index.tsx +18 -0
  534. package/src/components/tiptap/ui-primitive/spacer/spacer.tsx +40 -0
  535. package/src/components/tiptap/ui-primitive/textarea/index.tsx +18 -0
  536. package/src/components/tiptap/ui-primitive/textarea/textarea.scss +42 -0
  537. package/src/components/tiptap/ui-primitive/textarea/textarea.tsx +32 -0
  538. package/src/components/tiptap/ui-primitive/textarea-autosize/index.tsx +18 -0
  539. package/src/components/tiptap/ui-primitive/textarea-autosize/textarea-autosize.tsx +34 -0
  540. package/src/components/tiptap/ui-primitive/toolbar/index.tsx +18 -0
  541. package/src/components/tiptap/ui-primitive/toolbar/toolbar.scss +98 -0
  542. package/src/components/tiptap/ui-primitive/toolbar/toolbar.tsx +139 -0
  543. package/src/components/tiptap/ui-primitive/tooltip/index.tsx +18 -0
  544. package/src/components/tiptap/ui-primitive/tooltip/tooltip.scss +43 -0
  545. package/src/components/tiptap/ui-primitive/tooltip/tooltip.tsx +257 -0
  546. package/src/components/tiptap/ui-utils/floating-element/floating-element-utils.ts +51 -0
  547. package/src/components/tiptap/ui-utils/floating-element/floating-element.tsx +397 -0
  548. package/src/components/tiptap/ui-utils/floating-element/index.tsx +19 -0
  549. package/src/components/tiptap/ui-utils/suggestion-menu/index.tsx +20 -0
  550. package/src/components/tiptap/ui-utils/suggestion-menu/suggestion-menu-fullwidth.ts +48 -0
  551. package/src/components/tiptap/ui-utils/suggestion-menu/suggestion-menu-types.ts +119 -0
  552. package/src/components/tiptap/ui-utils/suggestion-menu/suggestion-menu-utils.ts +107 -0
  553. package/src/components/tiptap/ui-utils/suggestion-menu/suggestion-menu.tsx +367 -0
  554. package/src/components/tiptap/virtual.d.ts +17 -0
  555. package/src/components/ui/alert-dialog.tsx +1 -1
  556. package/src/components/ui/badge.tsx +1 -1
  557. package/src/components/ui/button.tsx +1 -1
  558. package/src/components/ui/card.tsx +1 -1
  559. package/src/components/ui/checkbox.tsx +1 -1
  560. package/src/components/ui/context-menu.tsx +1 -1
  561. package/src/components/ui/dialog.tsx +1 -1
  562. package/src/components/ui/dropdown-menu.tsx +1 -1
  563. package/src/components/ui/empty.tsx +1 -1
  564. package/src/components/ui/input.tsx +1 -1
  565. package/src/components/ui/label.tsx +1 -1
  566. package/src/components/ui/popover.tsx +1 -1
  567. package/src/components/ui/resizable.tsx +1 -1
  568. package/src/components/ui/select.tsx +1 -1
  569. package/src/components/ui/sidebar.tsx +1 -1
  570. package/src/components/ui/skeleton.tsx +1 -1
  571. package/src/components/ui/sonner.tsx +1 -1
  572. package/src/components/ui/spinner.tsx +1 -1
  573. package/src/components/ui/switch.tsx +1 -1
  574. package/src/components/ui/textarea.tsx +1 -1
  575. package/src/components/ui/tooltip.tsx +1 -1
  576. package/src/components/ui-shared/ai-command-button.tsx +36 -0
  577. package/src/components/ui-shared/ai-stream-text.tsx +37 -0
  578. package/src/components/ui-shared/alert-dialog.tsx +216 -0
  579. package/src/components/ui-shared/animated-theme-toggler.tsx +272 -0
  580. package/src/components/ui-shared/auth-client.ts +115 -0
  581. package/src/components/ui-shared/auth-layout.tsx +66 -0
  582. package/src/components/ui-shared/avatar.tsx +129 -0
  583. package/src/components/ui-shared/badge.tsx +66 -0
  584. package/src/components/ui-shared/button.tsx +84 -0
  585. package/src/components/ui-shared/card.tsx +120 -0
  586. package/src/components/ui-shared/checkbox.tsx +50 -0
  587. package/src/components/ui-shared/context-menu.tsx +280 -0
  588. package/src/components/ui-shared/dialog.tsx +183 -0
  589. package/src/components/ui-shared/dropdown-menu.tsx +286 -0
  590. package/src/components/ui-shared/empty.tsx +121 -0
  591. package/src/components/ui-shared/grid-pattern.tsx +87 -0
  592. package/src/components/ui-shared/index.ts +23 -0
  593. package/src/components/ui-shared/input.tsx +36 -0
  594. package/src/components/ui-shared/item.tsx +213 -0
  595. package/src/components/ui-shared/kbd.tsx +33 -0
  596. package/src/components/ui-shared/label.tsx +39 -0
  597. package/src/components/ui-shared/layout-panel-top.tsx +160 -0
  598. package/src/components/ui-shared/name-confirm-dialog.tsx +153 -0
  599. package/src/components/ui-shared/nav-float-button.tsx +301 -0
  600. package/src/components/ui-shared/notion-avatar.tsx +126 -0
  601. package/src/components/ui-shared/placeholder-page.tsx +42 -0
  602. package/src/components/ui-shared/popover.tsx +106 -0
  603. package/src/components/ui-shared/reference-inline.tsx +53 -0
  604. package/src/components/ui-shared/reference-search.tsx +52 -0
  605. package/src/components/ui-shared/resizable.tsx +67 -0
  606. package/src/components/ui-shared/select.tsx +207 -0
  607. package/src/components/ui-shared/separator.tsx +45 -0
  608. package/src/components/ui-shared/sheet.tsx +164 -0
  609. package/src/components/ui-shared/sidebar.tsx +708 -0
  610. package/src/components/ui-shared/skeleton.tsx +30 -0
  611. package/src/components/ui-shared/sonner.tsx +37 -0
  612. package/src/components/ui-shared/switch.tsx +48 -0
  613. package/src/components/ui-shared/textarea.tsx +35 -0
  614. package/src/components/ui-shared/timezone-provider.tsx +55 -0
  615. package/src/components/ui-shared/tooltip.tsx +72 -0
  616. package/src/components/ui-shared/use-mobile.ts +36 -0
  617. package/src/components/ui-shared/user-avatar.tsx +83 -0
  618. package/src/components/ui-shared/utils.ts +6 -0
  619. package/src/components/workspace/schemas/create-workspace.ts +1 -1
  620. package/src/hooks/use-entity-subscription.ts +1 -1
  621. package/src/hooks/use-notifications.ts +2 -2
  622. package/src/i18n/__tests__/detect.test.ts +48 -0
  623. package/src/i18n/__tests__/integration.test.tsx +32 -0
  624. package/src/i18n/__tests__/server.test.ts +33 -0
  625. package/src/i18n/client.ts +32 -0
  626. package/src/i18n/config.ts +114 -18
  627. package/src/i18n/detect.ts +43 -0
  628. package/src/i18n/locales/en/agents.json +134 -0
  629. package/src/i18n/locales/en/apps.json +6 -0
  630. package/src/i18n/locales/en/auth.json +90 -0
  631. package/src/i18n/locales/en/billing.json +78 -0
  632. package/src/i18n/locales/en/chat.json +194 -0
  633. package/src/i18n/locales/en/common.json +242 -0
  634. package/src/i18n/locales/en/dashboard.json +38 -0
  635. package/src/i18n/locales/en/design.json +70 -0
  636. package/src/i18n/locales/en/desktop.json +35 -0
  637. package/src/i18n/locales/en/display.json +37 -0
  638. package/src/i18n/locales/en/editor.json +304 -0
  639. package/src/i18n/locales/en/enterprise.json +1 -0
  640. package/src/i18n/locales/en/invite.json +56 -0
  641. package/src/i18n/locales/en/iterations.json +92 -0
  642. package/src/i18n/locales/en/knowledge.json +462 -0
  643. package/src/i18n/locales/en/mindmap.json +28 -0
  644. package/src/i18n/locales/en/notifications.json +79 -0
  645. package/src/i18n/locales/en/prd.json +51 -0
  646. package/src/i18n/locales/en/projects.json +140 -0
  647. package/src/i18n/locales/en/settings.json +428 -0
  648. package/src/i18n/locales/en/share.json +20 -0
  649. package/src/i18n/locales/en/story.json +923 -0
  650. package/src/i18n/locales/en/tags.json +42 -0
  651. package/src/i18n/locales/en/workspace.json +90 -0
  652. package/src/i18n/locales/zh/agents.json +134 -0
  653. package/src/i18n/locales/zh/apps.json +6 -0
  654. package/src/i18n/locales/zh/auth.json +90 -0
  655. package/src/i18n/locales/zh/billing.json +78 -0
  656. package/src/i18n/locales/zh/chat.json +194 -0
  657. package/src/i18n/locales/zh/common.json +242 -0
  658. package/src/i18n/locales/zh/dashboard.json +38 -0
  659. package/src/i18n/locales/zh/design.json +70 -0
  660. package/src/i18n/locales/zh/desktop.json +35 -0
  661. package/src/i18n/locales/zh/display.json +37 -0
  662. package/src/i18n/locales/zh/editor.json +304 -0
  663. package/src/i18n/locales/zh/enterprise.json +1 -0
  664. package/src/i18n/locales/zh/invite.json +56 -0
  665. package/src/i18n/locales/zh/iterations.json +92 -0
  666. package/src/i18n/locales/zh/knowledge.json +462 -0
  667. package/src/i18n/locales/zh/mindmap.json +28 -0
  668. package/src/i18n/locales/zh/notifications.json +79 -0
  669. package/src/i18n/locales/zh/prd.json +51 -0
  670. package/src/i18n/locales/zh/projects.json +140 -0
  671. package/src/i18n/locales/zh/settings.json +428 -0
  672. package/src/i18n/locales/zh/share.json +20 -0
  673. package/src/i18n/locales/zh/story.json +923 -0
  674. package/src/i18n/locales/zh/tags.json +42 -0
  675. package/src/i18n/locales/zh/workspace.json +90 -0
  676. package/src/i18n/server.ts +18 -0
  677. package/src/i18n/types.ts +5 -0
  678. package/src/lib/__tests__/ai-adapter.test.ts +5 -5
  679. package/src/lib/__tests__/cli-detector.test.ts +6 -6
  680. package/src/lib/__tests__/embedding.test.ts +1 -1
  681. package/src/lib/__tests__/module-registry.test.ts +1 -1
  682. package/src/lib/__tests__/provider-router.test.ts +2 -2
  683. package/src/lib/__tests__/rag.test.ts +1 -1
  684. package/src/lib/ai/__tests__/story-prompt.test.ts +1 -1
  685. package/src/lib/annotation-template.ts +33 -1
  686. package/src/lib/auth/auth-client.ts +1 -1
  687. package/src/lib/auth/auth.config.ts +1 -1
  688. package/src/lib/changelog/sdk-versions.ts +1 -8
  689. package/src/lib/collections/index.ts +1 -1
  690. package/src/lib/collections/knowledge/knowledge-bases-collection.ts +1 -1
  691. package/src/lib/collections/reference/bookmark-categories-collection.ts +1 -1
  692. package/src/lib/collections/reference/labels-collection.ts +1 -1
  693. package/src/lib/collections/reference/projects-collection.ts +1 -1
  694. package/src/lib/collections/reference/users-brief-collection.ts +1 -1
  695. package/src/lib/collections/reference/workspaces-collection.ts +1 -1
  696. package/src/lib/comment-utils.ts +47 -1
  697. package/src/lib/crypto/api-key-cipher.ts +1 -1
  698. package/src/lib/datetime.ts +130 -7
  699. package/src/lib/outline-utils.ts +57 -1
  700. package/src/lib/pacer.ts +96 -11
  701. package/src/lib/prd/__tests__/stack-layout.test.ts +1 -1
  702. package/src/lib/prd/stack-layout.ts +53 -1
  703. package/src/lib/prd-tree-utils.ts +94 -1
  704. package/src/lib/prototype-registry.ts +24 -1
  705. package/src/lib/query-client-seam.test.ts +19 -0
  706. package/src/lib/query-client-seam.ts +14 -0
  707. package/src/lib/rag.ts +1 -1
  708. package/src/lib/restore-version.ts +1 -1
  709. package/src/lib/router-context.ts +1 -1
  710. package/src/lib/share-events.ts +78 -1
  711. package/src/lib/sidebar-utils.ts +21 -1
  712. package/src/lib/sse-transport.ts +1 -1
  713. package/src/lib/stores/prd-canvas-store.ts +69 -1
  714. package/src/lib/tag-colors.ts +35 -1
  715. package/src/lib/time-format.ts +50 -1
  716. package/src/lib/utils.ts +1 -1
  717. package/src/plugins/core/context.ts +2 -0
  718. package/src/plugins/core/index.ts +1 -0
  719. package/src/plugins/core/inspiration/index.ts +17 -0
  720. package/src/plugins/core/inspiration/pages/inspiration-page.tsx +8 -0
  721. package/src/plugins/core/inspiration/routes.ts +12 -0
  722. package/src/plugins/core/inspiration/ui.tsx +28 -0
  723. package/src/plugins/core/prd/components/agent-input.tsx +193 -0
  724. package/src/plugins/core/prd/components/component-annotation-overlay/AnnotationOverlay.tsx +113 -0
  725. package/src/plugins/core/prd/components/component-editor/__tests__/field-utils.test.ts +93 -0
  726. package/src/plugins/core/prd/components/component-editor/collapsible-section.tsx +44 -0
  727. package/src/plugins/core/prd/components/component-editor/content-section.tsx +63 -0
  728. package/src/plugins/core/prd/components/component-editor/field-utils.ts +56 -0
  729. package/src/plugins/core/prd/components/component-editor/position-section.tsx +39 -0
  730. package/src/plugins/core/prd/components/component-editor/style-fields.tsx +187 -0
  731. package/src/plugins/core/prd/components/component-editor/use-field.ts +53 -0
  732. package/src/plugins/core/prd/components/component-thumbnail.tsx +109 -0
  733. package/src/plugins/core/prd/components/dialog/create-prd-dialog.tsx +148 -0
  734. package/src/plugins/core/prd/components/dialog/prd-detail-client.tsx +102 -0
  735. package/src/plugins/core/prd/components/element-context.ts +29 -0
  736. package/src/plugins/core/prd/components/index.ts +19 -0
  737. package/src/plugins/core/prd/components/page-version-panel/components/create-version-dialog.tsx +84 -0
  738. package/src/plugins/core/prd/components/page-version-panel/components/delete-version-dialog.tsx +61 -0
  739. package/src/plugins/core/prd/components/page-version-panel/components/edit-version-dialog.tsx +82 -0
  740. package/src/plugins/core/prd/components/page-version-panel/constants.tsx +23 -0
  741. package/src/plugins/core/prd/components/page-version-panel/types.ts +30 -0
  742. package/src/plugins/core/prd/components/page-version-panel.tsx +1100 -0
  743. package/src/plugins/core/prd/components/page-version-tree.tsx +308 -0
  744. package/src/plugins/core/prd/components/prd-agent-panel.tsx +429 -0
  745. package/src/plugins/core/prd/components/prd-comment-review-panel.tsx +227 -0
  746. package/src/plugins/core/prd/components/prd-component-editor-content.tsx +90 -0
  747. package/src/plugins/core/prd/components/prd-dashboard.tsx +302 -0
  748. package/src/plugins/core/prd/components/prd-doc-panel.tsx +116 -0
  749. package/src/plugins/core/prd/components/prd-editor-layout.tsx +466 -0
  750. package/src/plugins/core/prd/components/prd-filter-bar.tsx +103 -0
  751. package/src/plugins/core/prd/components/prd-left-sidebar.tsx +473 -0
  752. package/src/plugins/core/prd/components/prd-navigation.tsx +287 -0
  753. package/src/plugins/core/prd/components/prd-outline-tab.tsx +61 -0
  754. package/src/plugins/core/prd/components/prd-prototype-panel.tsx +142 -0
  755. package/src/plugins/core/prd/components/prd-right-sidebar.tsx +209 -0
  756. package/src/plugins/core/prd/components/prd-share-panel/components/single-version-share-card.tsx +201 -0
  757. package/src/plugins/core/prd/components/prd-share-panel/constants.ts +22 -0
  758. package/src/plugins/core/prd/components/prd-share-panel/types.ts +21 -0
  759. package/src/plugins/core/prd/components/prd-share-panel/utils.ts +30 -0
  760. package/src/plugins/core/prd/components/prd-share-panel.tsx +567 -0
  761. package/src/plugins/core/prd/components/prd-tree-page-tab.tsx +572 -0
  762. package/src/plugins/core/prd/components/prd-tree-reducer.ts +96 -0
  763. package/src/plugins/core/prd/components/prototype/IconPrototype.tsx +81 -0
  764. package/src/plugins/core/prd/components/prototype/PrototypeCanvas.tsx +411 -0
  765. package/src/plugins/core/prd/components/prototype/PrototypeElement.tsx +168 -0
  766. package/src/plugins/core/prd/components/prototype/ResizeHandles.tsx +95 -0
  767. package/src/plugins/core/prd/components/prototype/icon-components.ts +57 -0
  768. package/src/plugins/core/prd/components/prototype/imported/.gitkeep +0 -0
  769. package/src/plugins/core/prd/components/prototype/index.ts +31 -0
  770. package/src/plugins/core/prd/components/restore-version-dialog.tsx +76 -0
  771. package/src/plugins/core/prd/components/schemas/create-prd.ts +26 -0
  772. package/src/plugins/core/prd/components/share/prd-share-client.tsx +118 -0
  773. package/src/plugins/core/prd/components/share/share-annotation-overlay.tsx +122 -0
  774. package/src/plugins/core/prd/components/share/share-comment-panel.tsx +257 -0
  775. package/src/plugins/core/prd/components/share/share-comment-review-panel.tsx +75 -0
  776. package/src/plugins/core/prd/components/share/share-directory-tree.tsx +93 -0
  777. package/src/plugins/core/prd/components/share/share-doc-view.tsx +96 -0
  778. package/src/plugins/core/prd/components/share/share-layout.tsx +171 -0
  779. package/src/plugins/core/prd/components/share/share-nav-bar.tsx +72 -0
  780. package/src/plugins/core/prd/components/share/share-password-gate.tsx +90 -0
  781. package/src/plugins/core/prd/components/share/share-prototype-view.tsx +92 -0
  782. package/src/plugins/core/prd/components/share/share-review-panel.tsx +93 -0
  783. package/src/plugins/core/prd/components/share/share-sse-listener.tsx +76 -0
  784. package/src/plugins/core/prd/components/share/share-theme-toggle.tsx +57 -0
  785. package/src/plugins/core/prd/components/share/version-share-client.tsx +123 -0
  786. package/src/plugins/core/prd/components/tiptap/node/paragraph-node/paragraph-node.scss +286 -0
  787. package/src/plugins/core/prd/icon-picker-bridge.ts +41 -0
  788. package/src/plugins/core/prd/index.ts +40 -0
  789. package/src/plugins/core/prd/lib/ai/annotation-prompt.ts +66 -0
  790. package/src/plugins/core/prd/lib/restore-version.ts +53 -0
  791. package/src/plugins/core/prd/pages/prd-detail-page.tsx +88 -0
  792. package/src/plugins/core/prd/pages/prd-layout.tsx +28 -0
  793. package/src/plugins/core/prd/pages/share-prd-page.tsx +69 -0
  794. package/src/plugins/core/prd/prd-nav.tsx +92 -0
  795. package/src/plugins/core/prd/routes.tsx +103 -0
  796. package/src/plugins/core/prd/serverFns/ai/agent-conversations.ts +124 -0
  797. package/src/plugins/core/prd/serverFns/ai/fill-annotation.ts +80 -0
  798. package/src/plugins/core/prd/serverFns/ai/generate-prototype.ts +121 -0
  799. package/src/plugins/core/prd/serverFns/ai/providers.ts +528 -0
  800. package/src/plugins/core/prd/serverFns/comments.ts +109 -0
  801. package/src/plugins/core/prd/serverFns/components.ts +37 -0
  802. package/src/plugins/core/prd/serverFns/detail.ts +49 -0
  803. package/src/plugins/core/prd/serverFns/index.ts +14 -0
  804. package/src/plugins/core/prd/serverFns/page-versions.ts +137 -0
  805. package/src/plugins/core/prd/serverFns/pages.ts +164 -0
  806. package/src/plugins/core/prd/serverFns/prd.ts +164 -0
  807. package/src/plugins/core/prd/serverFns/reviews.ts +87 -0
  808. package/src/plugins/core/prd/serverFns/share/verify-password.ts +75 -0
  809. package/src/plugins/core/prd/serverFns/share/versions.ts +112 -0
  810. package/src/plugins/core/prd/serverFns/share.ts +119 -0
  811. package/src/plugins/core/prd/serverFns/shares-password.ts +189 -0
  812. package/src/plugins/core/prd/serverFns/shares.ts +336 -0
  813. package/src/plugins/core/prd/serverFns/versions.ts +277 -0
  814. package/src/plugins/core/prd/ui.ts +24 -0
  815. package/src/plugins/core/server/api-key-cipher.ts +61 -0
  816. package/src/plugins/core/server/rate-limit.ts +111 -0
  817. package/src/plugins/core/tags/__tests__/tags.test.ts +367 -0
  818. package/src/plugins/core/tags/index.ts +39 -0
  819. package/src/plugins/core/tags/nav-tag.tsx +137 -0
  820. package/src/plugins/core/tags/pages/tag-detail-page.tsx +31 -0
  821. package/src/plugins/core/tags/pages/tag-settings-page.tsx +34 -0
  822. package/src/plugins/core/tags/pages/tags-index-page.tsx +34 -0
  823. package/src/plugins/core/tags/routes.ts +65 -0
  824. package/src/plugins/core/tags/serverFns.ts +122 -0
  825. package/src/plugins/core/tags/tag-badge.tsx +57 -0
  826. package/src/plugins/core/tags/tag-color-classes.ts +61 -0
  827. package/src/plugins/core/tags/tag-color-picker.tsx +56 -0
  828. package/src/plugins/core/tags/tag-components-index.ts +23 -0
  829. package/src/plugins/core/tags/tag-manager.tsx +212 -0
  830. package/src/plugins/core/tags/tag-selector.tsx +169 -0
  831. package/src/plugins/core/tags/tags-collection.ts +40 -0
  832. package/src/plugins/core/tags/ui.ts +24 -0
  833. package/src/plugins/plugins.gen.ts +3 -3
  834. package/src/plugins/ui.gen.ts +1 -1
  835. package/src/providers/index.tsx +3 -3
  836. package/src/providers/timezone-provider.tsx +1 -1
  837. package/src/router.tsx +2 -2
  838. package/src/routes/__root.tsx +2 -2
  839. package/src/routes/_login/schemas/-auth.ts +1 -1
  840. package/src/routes/_nav/changelog/route.lazy.tsx +1 -1
  841. package/src/routes/_nav/changelog/route.tsx +1 -1
  842. package/src/routes/_nav/dashboard/-components/avatar-group.tsx +2 -2
  843. package/src/routes/_nav/dashboard/route.tsx +1 -1
  844. package/src/routes/_nav/inspiration/route.tsx +1 -1
  845. package/src/routes/_nav/notifications/route.tsx +1 -1
  846. package/src/routes/_nav/prd/$id/route.tsx +1 -1
  847. package/src/routes/_nav/prd/index.tsx +1 -1
  848. package/src/routes/_nav/prd/route.tsx +1 -1
  849. package/src/routes/_nav/projects/$projectId/index.lazy.tsx +1 -1
  850. package/src/routes/_nav/route.tsx +1 -1
  851. package/src/routes/_nav/settings/account/route.tsx +1 -1
  852. package/src/routes/_nav/settings/route.tsx +1 -1
  853. package/src/routes/_nav/tags/$id/route.tsx +1 -1
  854. package/src/routes/_nav/tags/index.tsx +1 -1
  855. package/src/routes/_nav/tags/route.tsx +1 -1
  856. package/src/routes/_nav/tags/settings/route.tsx +1 -1
  857. package/src/routes/api/auth/desktop-callback.ts +1 -1
  858. package/src/routes/api/chat.ts +2 -2
  859. package/src/routes/api/notifications/stream.ts +1 -1
  860. package/src/routes/api/story-ai.ts +1 -1
  861. package/src/routes/invite/$token/route.lazy.tsx +1 -1
  862. package/src/routes/server.ai-stream.ts +1 -1
  863. package/src/routes/share/$versionId/route.lazy.tsx +1 -1
  864. package/src/routes/share/prd/$prdId/route.tsx +1 -1
  865. package/src/server/__tests__/agent-client-graph.test.ts +8 -5
  866. package/src/server/__tests__/resource-registry.test.ts +1 -1
  867. package/src/server/ai-gateway/__tests__/conformance.test.ts +43 -0
  868. package/src/server/ai-gateway/__tests__/embedding-request.test.ts +84 -0
  869. package/src/server/ai-gateway/__tests__/embedding.test.ts +42 -0
  870. package/src/server/ai-gateway/__tests__/interrupt-store.test.ts +539 -0
  871. package/src/server/ai-gateway/__tests__/knowledge-scope.test.ts +207 -0
  872. package/src/server/ai-gateway/__tests__/label-suggest.test.ts +113 -0
  873. package/src/server/ai-gateway/__tests__/message-store.test.ts +197 -0
  874. package/src/server/ai-gateway/__tests__/rerank.test.ts +128 -0
  875. package/src/server/ai-gateway/__tests__/run-store.test.ts +378 -0
  876. package/src/server/ai-gateway/__tests__/runtime.test.ts +58 -0
  877. package/src/server/ai-gateway/__tests__/story-prompt.test.ts +34 -0
  878. package/src/server/ai-gateway/__tests__/tools-select.test.ts +103 -0
  879. package/src/server/ai-gateway/__tests__/unified-router.test.ts +124 -0
  880. package/src/server/ai-gateway/adapter.ts +255 -0
  881. package/src/server/ai-gateway/chat-handler.ts +238 -0
  882. package/src/server/ai-gateway/chat-stream-builder.ts +91 -0
  883. package/src/server/ai-gateway/connectivity-check.ts +148 -0
  884. package/src/server/ai-gateway/embedding.ts +67 -0
  885. package/src/server/ai-gateway/index.ts +111 -0
  886. package/src/server/ai-gateway/label-suggest.ts +126 -0
  887. package/src/server/ai-gateway/middlewares/index.ts +19 -0
  888. package/src/server/ai-gateway/middlewares/logger.ts +35 -0
  889. package/src/server/ai-gateway/middlewares/rate-limit.ts +40 -0
  890. package/src/server/ai-gateway/model-fetch.ts +168 -0
  891. package/src/server/ai-gateway/persistence/index.ts +36 -0
  892. package/src/server/ai-gateway/persistence/interrupt-store.ts +154 -0
  893. package/src/server/ai-gateway/persistence/message-store.ts +124 -0
  894. package/src/server/ai-gateway/persistence/run-store.ts +120 -0
  895. package/src/server/ai-gateway/ports.ts +71 -0
  896. package/src/server/ai-gateway/pro-services.ts +25 -0
  897. package/src/server/ai-gateway/provider-router.ts +238 -0
  898. package/src/server/ai-gateway/provider-tools.ts +42 -0
  899. package/src/server/ai-gateway/rerank.ts +63 -0
  900. package/src/server/ai-gateway/runtime.ts +42 -0
  901. package/src/server/ai-gateway/story-handler.ts +171 -0
  902. package/src/server/ai-gateway/story-prompt.ts +68 -0
  903. package/src/server/ai-gateway/tools/definitions.ts +99 -0
  904. package/src/server/ai-gateway/tools/delete-project.ts +39 -0
  905. package/src/server/ai-gateway/tools/index.ts +31 -0
  906. package/src/server/ai-gateway/tools/knowledge-scope.ts +56 -0
  907. package/src/server/ai-gateway/tools/select.ts +53 -0
  908. package/src/server/ai-gateway/tools/server.ts +198 -0
  909. package/src/server/ai-gateway/tools.ts +7 -0
  910. package/src/server/ai-gateway/types.ts +42 -0
  911. package/src/server/ai-gateway/unified-router.ts +180 -0
  912. package/src/server/ai-ports.ts +2 -2
  913. package/src/server/entitlements-token-client.ts +1 -1
  914. package/src/server/entitlements-token.ts +1 -1
  915. package/src/server/entitlements.ts +1 -1
  916. package/src/server/middlewares/rate-limit-server-fn.ts +1 -1
  917. package/src/server/notifications/event-bus.ts +1 -1
  918. package/src/server/notifications/notification-service.ts +3 -3
  919. package/src/server/resources.ts +1 -1
  920. package/src/server/serverFns/__tests__/knowledge-index.test.ts +1 -1
  921. package/src/server/serverFns/agents/agent-crud.ts +1 -1
  922. package/src/server/serverFns/agents/resolve-overrides.ts +2 -2
  923. package/src/server/serverFns/ai/agent-conversations.ts +1 -1
  924. package/src/server/serverFns/ai/fill-annotation.ts +1 -1
  925. package/src/server/serverFns/ai/generate-prototype.ts +1 -1
  926. package/src/server/serverFns/ai/providers.ts +1 -1
  927. package/src/server/serverFns/auth/session.ts +1 -1
  928. package/src/server/serverFns/billing.ts +1 -1
  929. package/src/server/serverFns/changelog/fetch.ts +1 -1
  930. package/src/server/serverFns/comments.ts +1 -1
  931. package/src/server/serverFns/components.ts +1 -1
  932. package/src/server/serverFns/knowledge-index-utils.ts +1 -1
  933. package/src/server/serverFns/locale.ts +1 -1
  934. package/src/server/serverFns/notifications.ts +1 -1
  935. package/src/server/serverFns/reviews.ts +1 -1
  936. package/src/server/serverFns/share/verify-password.ts +1 -1
  937. package/src/server/serverFns/share/versions.ts +1 -1
  938. package/src/server/serverFns/story/__tests__/label-suggest-fn.test.ts +2 -2
  939. package/src/server/serverFns/story/story-crud/label-suggest-core.ts +1 -1
  940. package/src/server/serverFns/translation.ts +1 -1
  941. package/src/shared/ai-cli/adapter.ts +59 -0
  942. package/src/shared/ai-cli/cli-detector.ts +64 -0
  943. package/src/start.ts +1 -1
  944. package/vite.shared.ts +1 -5
  945. package/src/lib/i18n/client.ts +0 -1
  946. package/src/lib/i18n/config.ts +0 -1
  947. package/src/lib/i18n/detect.ts +0 -1
  948. package/src/lib/i18n/server.ts +0 -1
  949. package/src/lib/i18n/types.ts +0 -1
@@ -0,0 +1,1100 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+
19
+ import React, { useState, useEffect, useCallback, useMemo, useRef } from "react";
20
+ import { useTranslation } from "react-i18next";
21
+ import { Button } from "@/components/ui-shared/button";
22
+ import { Input } from "@/components/ui-shared/input";
23
+ import { Skeleton } from "@/components/ui-shared/skeleton";
24
+ import { Checkbox } from "@/components/ui-shared/checkbox";
25
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui-shared/tooltip";
26
+ import {
27
+ Select,
28
+ SelectContent,
29
+ SelectItem,
30
+ SelectTrigger,
31
+ SelectValue,
32
+ } from "@/components/ui-shared/select";
33
+ import {
34
+ AlertDialog,
35
+ AlertDialogAction,
36
+ AlertDialogCancel,
37
+ AlertDialogContent,
38
+ AlertDialogDescription,
39
+ AlertDialogFooter,
40
+ AlertDialogHeader,
41
+ AlertDialogTitle,
42
+ } from "@/components/ui-shared/alert-dialog";
43
+ import { PageVersionTree, type VersionSnapshot } from "./page-version-tree";
44
+ import { executeRestoreVersion } from "@/plugins/core/prd/lib/restore-version";
45
+ import { RestoreVersionDialog } from "./restore-version-dialog";
46
+ import {
47
+ RefreshCw,
48
+ Folder,
49
+ File,
50
+ ChevronRight,
51
+ Plus,
52
+ Pencil,
53
+ RotateCcw,
54
+ Trash2,
55
+ } from "lucide-react";
56
+ import { cn } from "@/components/ui-shared/utils";
57
+ import { buildTree, TreeNode, PRDPage } from "@/lib/prd-tree-utils";
58
+ import { type PRDVersionWithSemver as PRDVersion } from "@allbluecn/shared";
59
+ import { SUBTABS } from "./page-version-panel/constants";
60
+ import { PageVersionPanelProps, type PageVersion } from "./page-version-panel/types";
61
+ import { CreateVersionDialog } from "./page-version-panel/components/create-version-dialog";
62
+ import { EditVersionDialog } from "./page-version-panel/components/edit-version-dialog";
63
+ import { DeleteVersionDialog } from "./page-version-panel/components/delete-version-dialog";
64
+ import { listPrdPagesFn } from "../serverFns/pages";
65
+ import { listPrdVersionsFn, createPrdVersionFn } from "../serverFns/versions";
66
+ import { listPrdPageVersionsFn, getPrdPageVersionFn, createPrdPageVersionFn, updatePrdPageVersionFn, deletePrdPageVersionFn } from "../serverFns/page-versions";
67
+ import { formatDate } from "@/lib/datetime";
68
+ import { useTimezone } from "@/components/ui-shared/timezone-provider";
69
+
70
+ export function PageVersionPanel({ prdId, pageId }: PageVersionPanelProps) {
71
+ const { t } = useTranslation(["prd", "common"]);
72
+ const [pages, setPages] = useState<PRDPage[]>([]);
73
+ const [tree, setTree] = useState<TreeNode[]>([]);
74
+ const [versions, setVersions] = useState<PRDVersion[]>([]);
75
+ const [selectedPageIds, setSelectedPageIds] = useState<Set<string>>(new Set());
76
+ const [selectedRestored, setSelectedRestored] = useState(false);
77
+ const [expandedNodes, setExpandedNodes] = useState<Set<string>>(new Set());
78
+ const [pagesLoading, setPagesLoading] = useState(true);
79
+ const [versionsLoading, setVersionsLoading] = useState(true);
80
+ const [pagesError, setPagesError] = useState("");
81
+ const [versionsError, setVersionsError] = useState("");
82
+ const [syncing, setSyncing] = useState(false);
83
+ const [major, setMajor] = useState("0");
84
+ const [minor, setMinor] = useState("1");
85
+ const [patch, setPatch] = useState("0");
86
+ const [notes, setNotes] = useState("");
87
+ const timezone = useTimezone();
88
+
89
+ const [pageVersions, setPageVersions] = useState<PageVersion[]>([]);
90
+ const [pageVersionsLoading, setPageVersionsLoading] = useState(false);
91
+ const [pageVersionsError, setPageVersionsError] = useState("");
92
+ const [creatingPageVersion, setCreatingPageVersion] = useState(false);
93
+
94
+ const latestPageIdRef = useRef<string | null>(null);
95
+
96
+ const [createDialogOpen, setCreateDialogOpen] = useState(false);
97
+ const [createDialogNotes, setCreateDialogNotes] = useState("");
98
+
99
+ const [editDialogOpen, setEditDialogOpen] = useState(false);
100
+ const [editDialogVersionId, setEditDialogVersionId] = useState<string | null>(null);
101
+ const [editDialogNotes, setEditDialogNotes] = useState("");
102
+
103
+ const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
104
+ const [deleteVersionId, setDeleteVersionId] = useState<string | null>(null);
105
+
106
+ const [restoreConfirmOpen, setRestoreConfirmOpen] = useState(false);
107
+ const [restoreLoading, setRestoreLoading] = useState(false);
108
+ const [restoreData, setRestoreData] = useState<{
109
+ pageId: string;
110
+ targetVersionNo: number;
111
+ targetCanvas: any;
112
+ targetContent: any;
113
+ currentVersionNo: number;
114
+ } | null>(null);
115
+
116
+ const [previewVersionId, setPreviewVersionId] = useState<string | null>(null);
117
+ const [expandedNotesId, setExpandedNotesId] = useState<string | null>(null);
118
+ const [selectedPageVersionNo, setSelectedPageVersionNo] = useState<Map<string, number>>(new Map());
119
+ const [allPageVersionsByPage, setAllPageVersionsByPage] = useState<Map<string, { version: number; notes: string | null; createdAt: string }[]>>(new Map());
120
+
121
+ useEffect(() => {
122
+ const nodeIdsWithChildren = new Set<string>();
123
+ const walk = (nodes: TreeNode[]) => {
124
+ for (const node of nodes) {
125
+ if (node.children.length > 0) nodeIdsWithChildren.add(node.id);
126
+ walk(node.children);
127
+ }
128
+ };
129
+ walk(tree);
130
+ setExpandedNodes((prev) => {
131
+ let hasNew = false;
132
+ for (const id of nodeIdsWithChildren) {
133
+ if (!prev.has(id)) {
134
+ hasNew = true;
135
+ break;
136
+ }
137
+ }
138
+ if (!hasNew) return prev;
139
+ const next = new Set(prev);
140
+ for (const id of nodeIdsWithChildren) next.add(id);
141
+ return next;
142
+ });
143
+ }, [tree]);
144
+
145
+ const getAllPageIds = useCallback((nodes: TreeNode[]): string[] => {
146
+ const ids: string[] = [];
147
+ const walk = (ns: TreeNode[]) => {
148
+ for (const n of ns) {
149
+ if (n.type === "page") ids.push(n.id);
150
+ walk(n.children);
151
+ }
152
+ };
153
+ walk(nodes);
154
+ return ids;
155
+ }, []);
156
+
157
+ const loadPages = useCallback((isSync: boolean = false) => {
158
+ if (!isSync) {
159
+ setPagesLoading(true);
160
+ }
161
+ setPagesError("");
162
+ setSyncing(true);
163
+ listPrdPagesFn({ data: { prdId } })
164
+ .then((data) => {
165
+ const pages = data as PRDPage[];
166
+ setPages(pages);
167
+ setTree(buildTree(pages));
168
+ setPagesLoading(false);
169
+ setSyncing(false);
170
+ })
171
+ .catch((err) => {
172
+ setPagesError(err.message);
173
+ setPagesLoading(false);
174
+ setSyncing(false);
175
+ });
176
+ }, [prdId]);
177
+
178
+ const createPageVersion = useCallback(async () => {
179
+ if (!pageId) return;
180
+ setCreatingPageVersion(true);
181
+ try {
182
+ const newVersion = await createPrdPageVersionFn({
183
+ data: {
184
+ pageId,
185
+ notes: createDialogNotes || undefined,
186
+ },
187
+ });
188
+ setPageVersions((prev) => [{ ...newVersion, createdAt: newVersion.createdAt.toISOString() }, ...prev]);
189
+ setCreateDialogOpen(false);
190
+ setCreateDialogNotes("");
191
+ } finally {
192
+ setCreatingPageVersion(false);
193
+ }
194
+ }, [pageId, createDialogNotes]);
195
+
196
+ const updatePageVersionNotes = useCallback(async () => {
197
+ if (!editDialogVersionId) return;
198
+ try {
199
+ const updated = await updatePrdPageVersionFn({
200
+ data: { pageVersionId: editDialogVersionId, notes: editDialogNotes || undefined },
201
+ });
202
+ setPageVersions((prev) => prev.map((v) => (v.id === updated.id ? { ...updated, createdAt: updated.createdAt.toISOString() } : v)));
203
+ setEditDialogOpen(false);
204
+ setEditDialogVersionId(null);
205
+ setEditDialogNotes("");
206
+ } catch {
207
+ // silent
208
+ }
209
+ }, [editDialogVersionId, editDialogNotes]);
210
+
211
+ const deletePageVersion = useCallback(async () => {
212
+ if (!deleteVersionId) return;
213
+ try {
214
+ await deletePrdPageVersionFn({ data: { pageVersionId: deleteVersionId } });
215
+ setPageVersions((prev) => prev.filter((v) => v.id !== deleteVersionId));
216
+ setDeleteConfirmOpen(false);
217
+ setDeleteVersionId(null);
218
+ } catch {
219
+ // silent
220
+ }
221
+ }, [deleteVersionId]);
222
+
223
+ const restorePageVersion = useCallback(
224
+ async (versionId: string) => {
225
+ const pv = await getPrdPageVersionFn({ data: { pageVersionId: versionId } });
226
+
227
+ const currentVersionNo = pageVersions[0]?.version ?? 0;
228
+ setRestoreData({
229
+ pageId: pv.pageId,
230
+ targetVersionNo: pv.version,
231
+ targetCanvas: pv.canvas,
232
+ targetContent: pv.content,
233
+ currentVersionNo,
234
+ });
235
+ setRestoreConfirmOpen(true);
236
+ },
237
+ [pageVersions]
238
+ );
239
+
240
+ const confirmRestore = useCallback(async () => {
241
+ if (!restoreData) return;
242
+ setRestoreLoading(true);
243
+ try {
244
+ await executeRestoreVersion(
245
+ restoreData.pageId,
246
+ restoreData.targetVersionNo,
247
+ restoreData.targetCanvas,
248
+ restoreData.targetContent,
249
+ );
250
+ setRestoreConfirmOpen(false);
251
+ setRestoreData(null);
252
+ listPrdPageVersionsFn({ data: { pageId: restoreData.pageId } })
253
+ .then((data) => setPageVersions(data.map((v) => ({ ...v, createdAt: v.createdAt.toISOString() }))));
254
+ } catch {
255
+ // silent
256
+ } finally {
257
+ setRestoreLoading(false);
258
+ }
259
+ }, [restoreData]);
260
+
261
+ const previewVersion = useCallback(async (versionId: string) => {
262
+ const isLatest = pageVersions.length > 0 && pageVersions[0].id === versionId;
263
+
264
+ if (previewVersionId === versionId || isLatest) {
265
+ setPreviewVersionId(null);
266
+ window.dispatchEvent(new CustomEvent("page-version-preview-end"));
267
+ return;
268
+ }
269
+
270
+ const pv = await getPrdPageVersionFn({ data: { pageVersionId: versionId } });
271
+ setPreviewVersionId(versionId);
272
+ window.dispatchEvent(new CustomEvent("page-version-preview", {
273
+ detail: { versionId, canvas: pv.canvas, content: pv.content },
274
+ }));
275
+ }, [previewVersionId, pageVersions]);
276
+
277
+ useEffect(() => {
278
+ loadPages();
279
+
280
+ // Restore selectedPageIds from localStorage
281
+ const stored = localStorage.getItem(`selectedPages_${prdId}`);
282
+ if (stored) {
283
+ try {
284
+ const ids = JSON.parse(stored);
285
+ if (Array.isArray(ids) && ids.length > 0) {
286
+ setSelectedPageIds(new Set(ids));
287
+ }
288
+ } catch { /* ignore */ }
289
+ }
290
+ setSelectedRestored(true);
291
+
292
+ setVersionsLoading(true);
293
+ setVersionsError("");
294
+ listPrdVersionsFn({ data: { prdId } })
295
+ .then((data) => {
296
+ const mapped = data.map((v) => ({ ...v, createdAt: v.createdAt.toISOString(), updatedAt: v.updatedAt?.toISOString() ?? null }));
297
+ setVersions(mapped);
298
+ setVersionsLoading(false);
299
+ if (mapped.length > 0) {
300
+ const sorted = [...mapped].sort((a, b) => {
301
+ if (a.major !== b.major) return b.major - a.major;
302
+ if (a.minor !== b.minor) return b.minor - a.minor;
303
+ return b.patch - a.patch;
304
+ });
305
+ const latest = sorted[0];
306
+ let nextPatch = latest.patch + 1;
307
+ let nextMinor = latest.minor;
308
+ let nextMajor = latest.major;
309
+ if (nextPatch > 99) { nextPatch = 0; nextMinor += 1; }
310
+ if (nextMinor > 99) { nextMinor = 0; nextMajor += 1; }
311
+ setMajor(String(nextMajor));
312
+ setMinor(String(nextMinor));
313
+ setPatch(String(nextPatch));
314
+ }
315
+ })
316
+ .catch((err) => {
317
+ setVersionsError(err.message);
318
+ setVersionsLoading(false);
319
+ });
320
+ }, [prdId, loadPages]);
321
+
322
+ useEffect(() => {
323
+ if (selectedRestored) {
324
+ localStorage.setItem(`selectedPages_${prdId}`, JSON.stringify(Array.from(selectedPageIds)));
325
+ }
326
+ }, [prdId, selectedPageIds, selectedRestored]);
327
+
328
+ useEffect(() => {
329
+ if (pageId) {
330
+ setPreviewVersionId(null);
331
+ latestPageIdRef.current = pageId;
332
+ setPageVersions([]);
333
+ setPageVersionsLoading(true);
334
+ setPageVersionsError("");
335
+
336
+ listPrdPageVersionsFn({ data: { pageId } })
337
+ .then((data) => {
338
+ if (latestPageIdRef.current === pageId) {
339
+ setPageVersions(data.map((v) => ({ ...v, createdAt: v.createdAt.toISOString() })));
340
+ setPageVersionsLoading(false);
341
+ }
342
+ })
343
+ .catch((err) => {
344
+ if (latestPageIdRef.current === pageId) {
345
+ setPageVersionsError(err.message);
346
+ setPageVersionsLoading(false);
347
+ }
348
+ });
349
+ } else {
350
+ latestPageIdRef.current = null;
351
+ setPageVersions([]);
352
+ setPageVersionsLoading(false);
353
+ setPageVersionsError("");
354
+ }
355
+ }, [pageId]);
356
+
357
+ const toggleNode = useCallback((id: string) => {
358
+ setExpandedNodes((prev) => {
359
+ const next = new Set(prev);
360
+ if (next.has(id)) next.delete(id);
361
+ else next.add(id);
362
+ return next;
363
+ });
364
+ }, []);
365
+
366
+ const getDescendantPageIds = useCallback((node: TreeNode): string[] => {
367
+ const ids: string[] = [];
368
+ const walk = (n: TreeNode) => {
369
+ if (n.type === "page") ids.push(n.id);
370
+ n.children.forEach(walk);
371
+ };
372
+ walk(node);
373
+ return ids;
374
+ }, []);
375
+
376
+ const togglePage = useCallback(
377
+ (id: string, node?: TreeNode) => {
378
+ setSelectedPageIds((prev) => {
379
+ const next = new Set(prev);
380
+ if (next.has(id)) {
381
+ next.delete(id);
382
+ if (node?.type === "folder") {
383
+ getDescendantPageIds(node).forEach((cid) => next.delete(cid));
384
+ }
385
+ } else {
386
+ next.add(id);
387
+ if (node?.type === "folder") {
388
+ getDescendantPageIds(node).forEach((cid) => next.add(cid));
389
+ }
390
+ }
391
+ return next;
392
+ });
393
+ },
394
+ [getDescendantPageIds]
395
+ );
396
+
397
+ const isFolderIndeterminate = useCallback(
398
+ (node: TreeNode): boolean => {
399
+ const childPageIds = getDescendantPageIds(node);
400
+ if (childPageIds.length === 0) return false;
401
+ const selectedCount = childPageIds.filter((id) => selectedPageIds.has(id)).length;
402
+ return selectedCount > 0 && selectedCount < childPageIds.length;
403
+ },
404
+ [selectedPageIds, getDescendantPageIds]
405
+ );
406
+
407
+ const isFolderAllSelected = useCallback(
408
+ (node: TreeNode): boolean => {
409
+ const childPageIds = getDescendantPageIds(node);
410
+ if (childPageIds.length === 0) return selectedPageIds.has(node.id);
411
+ return childPageIds.every((id) => selectedPageIds.has(id));
412
+ },
413
+ [selectedPageIds, getDescendantPageIds]
414
+ );
415
+
416
+ const [confirmUpdateOpen, setConfirmUpdateOpen] = useState(false);
417
+ const [confirmSkipOpen, setConfirmSkipOpen] = useState(false);
418
+ const [isUpdateMode, setIsUpdateMode] = useState(false);
419
+ const [versionTooLow, setVersionTooLow] = useState(false);
420
+ const [skipVersionInfo, setSkipVersionInfo] = useState<{ current: string; previous: string } | null>(null);
421
+
422
+ const executePublish = useCallback(async () => {
423
+ const selectedPageVersionsObj: Record<string, number> = {};
424
+ for (const [pid, versionNo] of selectedPageVersionNo) {
425
+ selectedPageVersionsObj[pid] = versionNo;
426
+ }
427
+ const version = (await createPrdVersionFn({
428
+ data: {
429
+ prdId,
430
+ major: parseInt(major),
431
+ minor: parseInt(minor),
432
+ patch: parseInt(patch),
433
+ notes,
434
+ pageIds: Array.from(selectedPageIds),
435
+ selectedPageVersions: selectedPageVersionsObj,
436
+ },
437
+ })) as unknown as PRDVersion;
438
+ setVersions((prev) => {
439
+ const filtered = prev.filter((v) => v.id !== version.id);
440
+ return [...filtered, version].sort((a, b) => {
441
+ if (a.major !== b.major) return b.major - a.major;
442
+ if (a.minor !== b.minor) return b.minor - a.minor;
443
+ return b.patch - a.patch;
444
+ });
445
+ });
446
+ setNotes("");
447
+ setIsUpdateMode(false);
448
+ }, [prdId, major, minor, patch, notes, selectedPageVersionNo, selectedPageIds]);
449
+
450
+ const publish = useCallback(() => {
451
+ if (isUpdateMode) {
452
+ setConfirmUpdateOpen(true);
453
+ } else {
454
+ const currentMajor = parseInt(major);
455
+ const currentMinor = parseInt(minor);
456
+ const currentPatch = parseInt(patch);
457
+
458
+ if (versions.length > 0) {
459
+ const sortedVersions = [...versions].sort((a, b) => {
460
+ if (a.major !== b.major) return b.major - a.major;
461
+ if (a.minor !== b.minor) return b.minor - a.minor;
462
+ return b.patch - a.patch;
463
+ });
464
+ const latestVersion = sortedVersions[0];
465
+
466
+ const expectedPatch = latestVersion.patch + 1;
467
+ const expectedMinor = latestVersion.minor + (latestVersion.patch === 99 ? 1 : 0);
468
+ const expectedMajor = latestVersion.major + (latestVersion.minor === 99 && latestVersion.patch === 99 ? 1 : 0);
469
+
470
+ const isConsecutive =
471
+ (currentPatch === expectedPatch && currentMinor === latestVersion.minor && currentMajor === latestVersion.major) ||
472
+ (currentPatch === 0 && currentMinor === expectedMinor && currentMajor === latestVersion.major) ||
473
+ (currentPatch === 0 && currentMinor === 0 && currentMajor === expectedMajor);
474
+
475
+ if (!isConsecutive) {
476
+ setSkipVersionInfo({
477
+ current: `${currentMajor}.${currentMinor}.${currentPatch}`,
478
+ previous: `${latestVersion.major}.${latestVersion.minor}.${latestVersion.patch}`,
479
+ });
480
+ setConfirmSkipOpen(true);
481
+ return;
482
+ }
483
+ }
484
+
485
+ executePublish();
486
+ }
487
+ }, [isUpdateMode, executePublish, major, minor, patch, versions]);
488
+
489
+ useEffect(() => {
490
+ const vNum = parseInt(major) * 10000 + parseInt(minor) * 100 + parseInt(patch);
491
+ const isExisting = versions.some((v) => v.major === parseInt(major) && v.minor === parseInt(minor) && v.patch === parseInt(patch));
492
+ setIsUpdateMode(isExisting);
493
+
494
+ let highest = 0;
495
+ for (const v of versions) {
496
+ const vn = v.major * 10000 + v.minor * 100 + v.patch;
497
+ if (vn > highest) highest = vn;
498
+ }
499
+ setVersionTooLow(highest > 0 && vNum < highest && !isExisting);
500
+ }, [major, minor, patch, versions]);
501
+
502
+ const formatTime = (iso: string) => {
503
+ const d = new Date(iso);
504
+ const now = new Date();
505
+ const diffMs = now.getTime() - d.getTime();
506
+ const diffMins = Math.floor(diffMs / 60000);
507
+ const diffHours = Math.floor(diffMs / 3600000);
508
+ const diffDays = Math.floor(diffMs / 86400000);
509
+
510
+ if (diffMins < 1) return t("version.justNow");
511
+ if (diffMins < 60) return t("version.minutesAgo", { count: diffMins });
512
+ if (diffHours < 24) return t("version.hoursAgo", { count: diffHours });
513
+ if (diffDays < 7) return t("version.daysAgo", { count: diffDays });
514
+
515
+ return formatDate(d, timezone, t("version.dateTimeFormat"));
516
+ };
517
+
518
+ const systemNote = (pv: PageVersion) => {
519
+ if (pv.restoredFromVersion) return t("version.restoredFrom", { version: pv.restoredFromVersion });
520
+ if (pv.version === 1) return t("version.initial");
521
+ return null;
522
+ };
523
+
524
+ const renderNode = (node: TreeNode, depth: number = 0) => {
525
+ const isExpanded = expandedNodes.has(node.id);
526
+ const hasChildren = node.children.length > 0;
527
+ const isFolder = node.type === "folder";
528
+ const childPageIds = getDescendantPageIds(node);
529
+ const isEmptyFolder = isFolder && childPageIds.length === 0;
530
+ const indeterminate = isFolder ? isFolderIndeterminate(node) : false;
531
+ const allSelected = isFolder ? isFolderAllSelected(node) : selectedPageIds.has(node.id);
532
+
533
+ return (
534
+ <div key={node.id}>
535
+ <label
536
+ className={cn(
537
+ "flex items-center gap-2 px-2 py-1 rounded transition-colors duration-100",
538
+ !isEmptyFolder && "hover:bg-muted/50 cursor-pointer",
539
+ isEmptyFolder && "text-muted-foreground/50"
540
+ )}
541
+ style={{ paddingLeft: `${12 + depth * 16}px` }}
542
+ >
543
+ <Checkbox
544
+ checked={isFolder && indeterminate ? "indeterminate" : allSelected}
545
+ disabled={isEmptyFolder}
546
+ onCheckedChange={() => {
547
+ if (!isEmptyFolder) {
548
+ togglePage(node.id, node);
549
+ }
550
+ }}
551
+ className={cn(
552
+ "size-3.5",
553
+ isEmptyFolder && "opacity-50 cursor-not-allowed"
554
+ )}
555
+ />
556
+
557
+ {hasChildren ? (
558
+ <button
559
+ type="button"
560
+ onClick={(e) => {
561
+ e.stopPropagation();
562
+ toggleNode(node.id);
563
+ }}
564
+ className="shrink-0 hover:bg-muted rounded p-0.5 -m-0.5"
565
+ >
566
+ <ChevronRight
567
+ className={cn(
568
+ "size-3.5 text-muted-foreground/60 transition-transform duration-150",
569
+ isExpanded && "rotate-90"
570
+ )}
571
+ />
572
+ </button>
573
+ ) : (
574
+ <span className="size-3.5 shrink-0" />
575
+ )}
576
+
577
+ {isFolder ? (
578
+ <Folder className="size-3.5 shrink-0 text-muted-foreground" />
579
+ ) : (
580
+ <File className="size-3.5 shrink-0 text-muted-foreground" />
581
+ )}
582
+
583
+ <span className="flex-1 text-xs truncate">{node.name}</span>
584
+ {!isFolder && (
585
+ isPublishTab ? (
586
+ (allPageVersionsByPage.get(node.id) || []).length > 1 ? (
587
+ <Select
588
+ value={String(selectedPageVersionNo.get(node.id) ?? node.version)}
589
+ onValueChange={(value) => {
590
+ setSelectedPageVersionNo((prev) => {
591
+ const next = new Map(prev);
592
+ next.set(node.id, parseInt(value));
593
+ return next;
594
+ });
595
+ }}
596
+ >
597
+ <SelectTrigger
598
+ className="!h-4 text-[10px] px-1 py-0 gap-0 border-none shadow-none bg-transparent text-muted-foreground cursor-pointer [&_svg]:size-3"
599
+ onClick={(e) => e.stopPropagation()}
600
+ >
601
+ <SelectValue />
602
+ </SelectTrigger>
603
+ <SelectContent>
604
+ {(allPageVersionsByPage.get(node.id) || []).map((pv) => (
605
+ <SelectItem key={pv.version} value={String(pv.version)} className="text-xs">
606
+ PAGE v{pv.version}
607
+ </SelectItem>
608
+ ))}
609
+ </SelectContent>
610
+ </Select>
611
+ ) : (
612
+ <span className="text-[10px] text-muted-foreground">PAGE v{node.version}</span>
613
+ )
614
+ ) : (
615
+ <span className="text-[10px] text-muted-foreground">PAGE v{node.version}</span>
616
+ )
617
+ )}
618
+ </label>
619
+
620
+ {isExpanded && hasChildren && (
621
+ <div>{node.children.map((child) => renderNode(child, depth + 1))}</div>
622
+ )}
623
+ </div>
624
+ );
625
+ };
626
+
627
+ const selectedCount = useMemo(() => {
628
+ const allPageIds = getAllPageIds(tree);
629
+ return allPageIds.filter((id) => selectedPageIds.has(id)).length;
630
+ }, [tree, selectedPageIds, getAllPageIds]);
631
+
632
+ const allLeafPageIds = useMemo(() => {
633
+ return getAllPageIds(tree);
634
+ }, [tree, getAllPageIds]);
635
+
636
+ const allPagesSelected = useMemo(() => {
637
+ return allLeafPageIds.length > 0 && allLeafPageIds.every((id) => selectedPageIds.has(id));
638
+ }, [allLeafPageIds, selectedPageIds]);
639
+
640
+ const allPagesCount = allLeafPageIds.length;
641
+ const selectedRealCount = allLeafPageIds.filter((id) => selectedPageIds.has(id)).length;
642
+ const indeterminateAll = selectedRealCount > 0 && selectedRealCount < allPagesCount;
643
+
644
+ const selectLatestPages = useCallback(() => {
645
+ if (versions.length === 0) return;
646
+ const latest = versions[0];
647
+ const pageVersions = (latest as any).pageVersions as any[] | undefined;
648
+ if (!pageVersions) return;
649
+ const publishedPageIds = pageVersions
650
+ .filter((pv: any) => pv.type === "page" && !pv.isPlaceholder)
651
+ .map((pv: any) => pv.pageId);
652
+ const allIds = getAllPageIds(tree);
653
+ const validIds = publishedPageIds.filter((id: string) => allIds.includes(id));
654
+ setSelectedPageIds(new Set(validIds));
655
+ }, [versions, tree, getAllPageIds]);
656
+
657
+ const [activeSubTab, setActiveSubTab] = useState<string>("page-version");
658
+
659
+ const isPublishTab = activeSubTab === "version-publish";
660
+
661
+ // Fetch page version options for all leaf pages when publish tab is active
662
+ useEffect(() => {
663
+ if (!isPublishTab) return;
664
+ const allPageIds = getAllPageIds(tree);
665
+ const leafIds = allPageIds.filter((id) => selectedPageIds.has(id));
666
+ if (leafIds.length === 0) return;
667
+ const fetchVersions = async () => {
668
+ const results = await Promise.all(
669
+ leafIds.map(async (pid) => {
670
+ const versions = await listPrdPageVersionsFn({ data: { pageId: pid, limit: 100 } });
671
+ return { pageId: pid, versions };
672
+ })
673
+ );
674
+ const map = new Map<string, PageVersion[]>();
675
+ for (const r of results) {
676
+ if (r) map.set(r.pageId, r.versions.map((v) => ({ ...v, createdAt: v.createdAt.toISOString() })));
677
+ }
678
+ setAllPageVersionsByPage(map);
679
+ setSelectedPageVersionNo((prev) => {
680
+ const next = new Map(prev);
681
+ for (const r of results) {
682
+ if (r && r.versions.length > 0 && !next.has(r.pageId)) {
683
+ next.set(r.pageId, r.versions[0].version);
684
+ }
685
+ }
686
+ return next;
687
+ });
688
+ };
689
+ fetchVersions();
690
+ }, [isPublishTab, selectedPageIds, tree, getAllPageIds]);
691
+
692
+ return (
693
+ <div className="flex flex-col h-full">
694
+ <div className="shrink-0 flex items-center h-10 mt-2">
695
+ {SUBTABS.map((tab) => (
696
+ <button
697
+ key={tab.key}
698
+ onClick={() => setActiveSubTab(tab.key)}
699
+ className={cn(
700
+ "flex-1 flex items-center justify-center gap-1.5 text-xs font-medium h-full transition-colors",
701
+ activeSubTab === tab.key
702
+ ? "text-foreground border-b-2 border-primary"
703
+ : "text-muted-foreground hover:text-foreground"
704
+ )}
705
+ >
706
+ {tab.icon} {t(tab.label)}
707
+ </button>
708
+ ))}
709
+ </div>
710
+
711
+ {activeSubTab === "page-version" ? (
712
+ <div className="flex flex-col h-full p-3 text-sm">
713
+ <div className="shrink-0 flex items-center justify-between mb-4">
714
+ <h4 className="text-xs font-medium text-muted-foreground">{t("version.pageVersionHistory")}</h4>
715
+ <Button
716
+ size="sm"
717
+ variant="ghost"
718
+ className="h-6 text-xs gap-1"
719
+ disabled={!pageId || creatingPageVersion}
720
+ onClick={() => {
721
+ setCreateDialogNotes("");
722
+ setCreateDialogOpen(true);
723
+ }}
724
+ >
725
+ <Plus className="size-3.5" />
726
+ {t("version.createVersion")}
727
+ </Button>
728
+ </div>
729
+
730
+ <div className="min-h-0 overflow-y-auto flex-1">
731
+ {!pageId ? (
732
+ <div className="text-xs text-muted-foreground text-center py-8">
733
+ {t("version.selectPageHint")}
734
+ </div>
735
+ ) : pageVersionsLoading ? (
736
+ <div className="space-y-2 pt-2">
737
+ <Skeleton className="h-10 w-full rounded opacity-40" />
738
+ <Skeleton className="h-10 w-[85%] rounded opacity-40" />
739
+ <Skeleton className="h-10 w-[70%] rounded opacity-40" />
740
+ </div>
741
+ ) : pageVersionsError ? (
742
+ <p className="text-xs text-destructive text-center py-2">{pageVersionsError}</p>
743
+ ) : (
744
+ <div>
745
+ {pageVersions.map((pv, index) => {
746
+ const isLast = index === pageVersions.length - 1;
747
+ const isPreviewing = previewVersionId === pv.id;
748
+
749
+ return (
750
+ <div key={pv.id} className="relative">
751
+ <div className="flex gap-2">
752
+ <div className="flex flex-col items-center w-5">
753
+ <div
754
+ className={cn(
755
+ "size-2.5 rounded-full shrink-0 mt-1 z-10 relative",
756
+ isPreviewing
757
+ ? "bg-primary ring-2 ring-primary/30"
758
+ : index === 0 && !previewVersionId
759
+ ? "bg-primary"
760
+ : "bg-muted-foreground/40"
761
+ )}
762
+ />
763
+ {!isLast && <div className="w-px bg-border flex-1" />}
764
+ </div>
765
+
766
+ <div className="flex-1 min-w-0 pb-2">
767
+ <div
768
+ className="flex items-center justify-between gap-2 cursor-pointer rounded-sm px-1 -mx-1 hover:bg-muted/30 transition-colors py-0.5"
769
+ onClick={() => previewVersion(pv.id)}
770
+ >
771
+ <span
772
+ className={cn(
773
+ "text-xs font-medium truncate",
774
+ isPreviewing
775
+ ? "text-primary"
776
+ : index === 0 && !previewVersionId
777
+ ? "text-foreground"
778
+ : "text-muted-foreground"
779
+ )}
780
+ >
781
+ v{pv.version}
782
+ <span className="text-[10px] text-muted-foreground/70 ml-2">
783
+ {formatTime(pv.createdAt)}
784
+ </span>
785
+ {systemNote(pv) && (
786
+ <span className="text-[10px] text-muted-foreground/50 ml-2">
787
+ {systemNote(pv)}
788
+ </span>
789
+ )}
790
+ </span>
791
+
792
+ <div className="flex items-center gap-0.5 shrink-0" onClick={(e) => e.stopPropagation()}>
793
+ <Tooltip>
794
+ <TooltipTrigger asChild>
795
+ <button
796
+ onClick={() => restorePageVersion(pv.id)}
797
+ className="size-5 flex items-center justify-center rounded hover:bg-muted text-muted-foreground/50 hover:text-foreground transition-colors"
798
+ >
799
+ <RotateCcw className="size-3" />
800
+ </button>
801
+ </TooltipTrigger>
802
+ <TooltipContent>
803
+ <p>{t("version.restoreToThis")}</p>
804
+ </TooltipContent>
805
+ </Tooltip>
806
+ <Tooltip>
807
+ <TooltipTrigger asChild>
808
+ <button
809
+ onClick={() => {
810
+ setEditDialogVersionId(pv.id);
811
+ setEditDialogNotes(pv.notes || "");
812
+ setEditDialogOpen(true);
813
+ }}
814
+ className="size-5 flex items-center justify-center rounded hover:bg-muted text-muted-foreground/50 hover:text-foreground transition-colors"
815
+ >
816
+ <Pencil className="size-3" />
817
+ </button>
818
+ </TooltipTrigger>
819
+ <TooltipContent>
820
+ <p>{t("version.editNotes")}</p>
821
+ </TooltipContent>
822
+ </Tooltip>
823
+ <Tooltip>
824
+ <TooltipTrigger asChild>
825
+ <button
826
+ onClick={() => {
827
+ setDeleteVersionId(pv.id);
828
+ setDeleteConfirmOpen(true);
829
+ }}
830
+ className="size-5 flex items-center justify-center rounded hover:bg-destructive/10 text-muted-foreground/50 hover:text-destructive transition-colors"
831
+ >
832
+ <Trash2 className="size-3" />
833
+ </button>
834
+ </TooltipTrigger>
835
+ <TooltipContent>
836
+ <p>{t("version.deleteVersion")}</p>
837
+ </TooltipContent>
838
+ </Tooltip>
839
+ </div>
840
+ </div>
841
+ {pv.notes && (
842
+ <p
843
+ className={cn(
844
+ "text-xs text-muted-foreground mt-1 px-1 cursor-pointer hover:text-foreground transition-colors",
845
+ expandedNotesId !== pv.id && "line-clamp-2"
846
+ )}
847
+ onClick={() => setExpandedNotesId(expandedNotesId === pv.id ? null : pv.id)}
848
+ >
849
+ {pv.notes}
850
+ </p>
851
+ )}
852
+ </div>
853
+ </div>
854
+ </div>
855
+ );
856
+ })}
857
+ </div>
858
+ )}
859
+ </div>
860
+ </div>
861
+ ) : (
862
+ <div className="flex flex-col h-full p-3 text-sm">
863
+ <div className="flex flex-col shrink-0">
864
+ <div className="flex items-center justify-between mb-2">
865
+ <h4 className="text-xs font-medium text-muted-foreground">{t("version.selectPagesTitle")}</h4>
866
+ <div className="flex items-center gap-2">
867
+ <span className="text-[10px] text-muted-foreground/60">
868
+ {t("version.selectedCount", { count: selectedCount })}
869
+ </span>
870
+ <Tooltip>
871
+ <TooltipTrigger asChild>
872
+ <button
873
+ onClick={() => loadPages(true)}
874
+ disabled={syncing || pagesLoading}
875
+ className="size-5 flex items-center justify-center rounded hover:bg-muted text-muted-foreground/50 hover:text-muted-foreground transition-colors"
876
+ >
877
+ <RefreshCw
878
+ className={cn("size-3.5", syncing && "animate-spin")}
879
+ />
880
+ </button>
881
+ </TooltipTrigger>
882
+ <TooltipContent>
883
+ <p>{t("version.syncPages")}</p>
884
+ </TooltipContent>
885
+ </Tooltip>
886
+ </div>
887
+ </div>
888
+ <div className="flex items-center gap-2 px-2 py-1 mb-1.5">
889
+ <label className="flex items-center gap-1.5 cursor-pointer ml-1">
890
+ <Checkbox
891
+ checked={indeterminateAll ? "indeterminate" : allPagesSelected}
892
+ onCheckedChange={() => {
893
+ if (allPagesSelected) {
894
+ setSelectedPageIds(new Set());
895
+ } else {
896
+ setSelectedPageIds(new Set(allLeafPageIds));
897
+ }
898
+ }}
899
+ className="size-3.5"
900
+ />
901
+ <span className="text-[10px] text-muted-foreground">{t("version.selectAll")}</span>
902
+ </label>
903
+ <Tooltip>
904
+ <TooltipTrigger asChild>
905
+ <button
906
+ onClick={selectLatestPages}
907
+ className="text-[10px] text-muted-foreground hover:text-foreground ml-2 "
908
+ >
909
+ {t("version.selectLatest")}
910
+ </button>
911
+ </TooltipTrigger>
912
+ <TooltipContent>
913
+ <p>{t("version.selectLatestHint")}</p>
914
+ </TooltipContent>
915
+ </Tooltip>
916
+ </div>
917
+ <div className="space-y-0.5 max-h-[25vh] overflow-y-auto">
918
+ {pagesLoading ? (
919
+ <div className="space-y-2 pt-1">
920
+ <Skeleton className="h-5 w-full rounded opacity-40" />
921
+ <Skeleton className="h-5 w-[80%] rounded opacity-40" />
922
+ <Skeleton className="h-5 w-[60%] rounded opacity-40" />
923
+ </div>
924
+ ) : pagesError ? (
925
+ <p className="text-xs text-destructive text-center py-2">{pagesError}</p>
926
+ ) : tree.length === 0 ? (
927
+ <p className="text-xs text-muted-foreground text-center py-2">{t("version.noPages")}</p>
928
+ ) : (
929
+ tree.map((node) => renderNode(node))
930
+ )}
931
+ </div>
932
+ </div>
933
+
934
+ <div className="shrink-0 mt-4">
935
+ <h4 className="text-xs font-medium text-muted-foreground mb-2">{t("version.prdVersionNo")}</h4>
936
+ <div className="flex items-center gap-1">
937
+ <Input
938
+ value={major}
939
+ onChange={(e) => setMajor(e.target.value)}
940
+ className="h-6 w-12 text-xs md:text-xs text-center"
941
+ />
942
+ <span className="text-muted-foreground">.</span>
943
+ <Input
944
+ value={minor}
945
+ onChange={(e) => setMinor(e.target.value)}
946
+ className="h-6 w-12 text-xs md:text-xs text-center"
947
+ />
948
+ <span className="text-muted-foreground">.</span>
949
+ <Input
950
+ value={patch}
951
+ onChange={(e) => setPatch(e.target.value)}
952
+ className="h-6 w-12 text-xs md:text-xs text-center"
953
+ />
954
+ </div>
955
+ <Input
956
+ value={notes}
957
+ onChange={(e) => setNotes(e.target.value)}
958
+ placeholder={t("version.releaseNotesPlaceholder")}
959
+ className="h-7 text-xs md:text-xs mt-2"
960
+ />
961
+ <Tooltip>
962
+ <TooltipTrigger asChild>
963
+ <span tabIndex={0}>
964
+ <Button
965
+ size="sm"
966
+ className="w-full mt-2 h-7 text-xs"
967
+ disabled={selectedPageIds.size === 0 || versionTooLow}
968
+ onClick={publish}
969
+ >
970
+ {isUpdateMode ? t("version.update") : t("version.publish")} v{major}.{minor}.{patch} PRD
971
+ </Button>
972
+ </span>
973
+ </TooltipTrigger>
974
+ {versionTooLow && (
975
+ <TooltipContent>
976
+ <p>{t("version.versionTooLow")}</p>
977
+ </TooltipContent>
978
+ )}
979
+ </Tooltip>
980
+ <AlertDialog open={confirmUpdateOpen} onOpenChange={setConfirmUpdateOpen}>
981
+ <AlertDialogContent>
982
+ <AlertDialogHeader>
983
+ <AlertDialogTitle>{t("version.confirmUpdateTitle")}</AlertDialogTitle>
984
+ <AlertDialogDescription>
985
+ {t("version.confirmUpdateDescription", { version: `v${major}.${minor}.${patch}` })}
986
+ </AlertDialogDescription>
987
+ </AlertDialogHeader>
988
+ <AlertDialogFooter>
989
+ <AlertDialogCancel>{t("common:button.cancel")}</AlertDialogCancel>
990
+ <AlertDialogAction onClick={executePublish}>{t("version.confirmUpdate")}</AlertDialogAction>
991
+ </AlertDialogFooter>
992
+ </AlertDialogContent>
993
+ </AlertDialog>
994
+ <AlertDialog open={confirmSkipOpen} onOpenChange={setConfirmSkipOpen}>
995
+ <AlertDialogContent>
996
+ <AlertDialogHeader>
997
+ <AlertDialogTitle>{t("version.skipVersionTitle")}</AlertDialogTitle>
998
+ <AlertDialogDescription>
999
+ {t("version.skipVersionDescription", { current: skipVersionInfo?.current, previous: skipVersionInfo?.previous })}
1000
+ </AlertDialogDescription>
1001
+ </AlertDialogHeader>
1002
+ <AlertDialogFooter>
1003
+ <AlertDialogCancel>{t("common:button.cancel")}</AlertDialogCancel>
1004
+ <AlertDialogAction onClick={executePublish}>{t("version.continuePublish")}</AlertDialogAction>
1005
+ </AlertDialogFooter>
1006
+ </AlertDialogContent>
1007
+ </AlertDialog>
1008
+ </div>
1009
+
1010
+ <div className="flex flex-col min-h-0 mt-4 flex-1">
1011
+ <h4 className="text-xs font-medium text-muted-foreground mb-2 shrink-0">{t("version.prdVersionHistory")}</h4>
1012
+ <div className="min-h-0 overflow-y-auto flex-1">
1013
+ {versionsLoading ? (
1014
+ <div className="space-y-2 pt-2">
1015
+ <Skeleton className="h-5 w-full rounded opacity-40" />
1016
+ <Skeleton className="h-5 w-[75%] rounded opacity-40" />
1017
+ <Skeleton className="h-5 w-[60%] rounded opacity-40" />
1018
+ </div>
1019
+ ) : versionsError ? (
1020
+ <p className="text-xs text-destructive text-center py-2">{versionsError}</p>
1021
+ ) : versions.length === 0 ? (
1022
+ <div className="space-y-2 pt-3 pb-1">
1023
+ <Skeleton className="h-5 w-full rounded opacity-40" />
1024
+ <Skeleton className="h-5 w-[70%] rounded opacity-40" />
1025
+ <div className="pt-3 text-center">
1026
+ <p className="text-[11px] text-muted-foreground">{t("version.noPublishedVersions")}</p>
1027
+ </div>
1028
+ </div>
1029
+ ) : (
1030
+ <PageVersionTree
1031
+ versions={versions as any[]}
1032
+ onRestore={async (snapshot: VersionSnapshot) => {
1033
+ let targetCanvas = snapshot.canvas;
1034
+ let targetContent = snapshot.content;
1035
+ if (snapshot.pageVersionId && !targetCanvas) {
1036
+ const pv = await getPrdPageVersionFn({ data: { pageVersionId: snapshot.pageVersionId } });
1037
+ targetCanvas = pv.canvas;
1038
+ targetContent = pv.content;
1039
+ }
1040
+ try {
1041
+ const latest = await listPrdPageVersionsFn({ data: { pageId: snapshot.pageId, limit: 1 } });
1042
+ const currentVersionNo = latest[0]?.version ?? 0;
1043
+ setRestoreData({
1044
+ pageId: snapshot.pageId,
1045
+ targetVersionNo: snapshot.version,
1046
+ targetCanvas,
1047
+ targetContent,
1048
+ currentVersionNo,
1049
+ });
1050
+ setRestoreConfirmOpen(true);
1051
+ } catch {
1052
+ // silent
1053
+ }
1054
+ }}
1055
+ />
1056
+ )}
1057
+ </div>
1058
+ </div>
1059
+ </div>
1060
+ )}
1061
+
1062
+ <CreateVersionDialog
1063
+ open={createDialogOpen}
1064
+ onOpenChange={setCreateDialogOpen}
1065
+ notes={createDialogNotes}
1066
+ setNotes={setCreateDialogNotes}
1067
+ loading={creatingPageVersion}
1068
+ onCreate={createPageVersion}
1069
+ />
1070
+
1071
+ <EditVersionDialog
1072
+ open={editDialogOpen}
1073
+ onOpenChange={setEditDialogOpen}
1074
+ notes={editDialogNotes}
1075
+ setNotes={setEditDialogNotes}
1076
+ onSave={updatePageVersionNotes}
1077
+ />
1078
+
1079
+ <DeleteVersionDialog
1080
+ open={deleteConfirmOpen}
1081
+ onOpenChange={setDeleteConfirmOpen}
1082
+ onDelete={deletePageVersion}
1083
+ />
1084
+
1085
+ {restoreData && (
1086
+ <RestoreVersionDialog
1087
+ open={restoreConfirmOpen}
1088
+ onOpenChange={(open) => {
1089
+ setRestoreConfirmOpen(open);
1090
+ if (!open) setRestoreData(null);
1091
+ }}
1092
+ currentVersionNo={restoreData.currentVersionNo}
1093
+ targetVersionNo={restoreData.targetVersionNo}
1094
+ onConfirm={confirmRestore}
1095
+ loading={restoreLoading}
1096
+ />
1097
+ )}
1098
+ </div>
1099
+ );
1100
+ }