create-weave-frontend-app 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/README.md +11 -0
  2. package/dist/chunk-HZJMO45D.js +437 -0
  3. package/dist/create-app.d.ts +14 -0
  4. package/dist/create-app.js +6 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +106 -0
  7. package/package.json +65 -0
  8. package/template/+nextjs+azure-web-pubsub/README.md +36 -0
  9. package/template/+nextjs+azure-web-pubsub/api/del-image.ts +8 -0
  10. package/template/+nextjs+azure-web-pubsub/api/get-images.ts +15 -0
  11. package/template/+nextjs+azure-web-pubsub/api/post-image.ts +14 -0
  12. package/template/+nextjs+azure-web-pubsub/api/post-remove-background.ts +10 -0
  13. package/template/+nextjs+azure-web-pubsub/app/error/page.tsx +10 -0
  14. package/template/+nextjs+azure-web-pubsub/app/favicon.ico +0 -0
  15. package/template/+nextjs+azure-web-pubsub/app/globals.css +193 -0
  16. package/template/+nextjs+azure-web-pubsub/app/layout.tsx +46 -0
  17. package/template/+nextjs+azure-web-pubsub/app/page.tsx +7 -0
  18. package/template/+nextjs+azure-web-pubsub/app/providers.tsx +18 -0
  19. package/template/+nextjs+azure-web-pubsub/app/room/[roomId]/page.tsx +5 -0
  20. package/template/+nextjs+azure-web-pubsub/assets/images/home.png +0 -0
  21. package/template/+nextjs+azure-web-pubsub/assets/images/logo.png +0 -0
  22. package/template/+nextjs+azure-web-pubsub/components/actions/align-elements-tool/align-elements-tool.ts +94 -0
  23. package/template/+nextjs+azure-web-pubsub/components/actions/color-token-tool/color-token-tool.ts +164 -0
  24. package/template/+nextjs+azure-web-pubsub/components/actions/color-token-tool/constants.ts +5 -0
  25. package/template/+nextjs+azure-web-pubsub/components/actions/color-token-tool/types.ts +12 -0
  26. package/template/+nextjs+azure-web-pubsub/components/error/error.tsx +62 -0
  27. package/template/+nextjs+azure-web-pubsub/components/error/errors.ts +35 -0
  28. package/template/+nextjs+azure-web-pubsub/components/home/home.tsx +92 -0
  29. package/template/+nextjs+azure-web-pubsub/components/home-components/home-showcase-animation.tsx +119 -0
  30. package/template/+nextjs+azure-web-pubsub/components/home-components/login-form.tsx +117 -0
  31. package/template/+nextjs+azure-web-pubsub/components/nodes/color-token/color-token.ts +171 -0
  32. package/template/+nextjs+azure-web-pubsub/components/room/room.layout.tsx +115 -0
  33. package/template/+nextjs+azure-web-pubsub/components/room/room.tsx +125 -0
  34. package/template/+nextjs+azure-web-pubsub/components/room-components/color-tokens-library/color-token.tsx +31 -0
  35. package/template/+nextjs+azure-web-pubsub/components/room-components/color-tokens-library/color-tokens-library.tsx +64 -0
  36. package/template/+nextjs+azure-web-pubsub/components/room-components/connected-users.tsx +152 -0
  37. package/template/+nextjs+azure-web-pubsub/components/room-components/connection-status.tsx +52 -0
  38. package/template/+nextjs+azure-web-pubsub/components/room-components/context-menu.tsx +152 -0
  39. package/template/+nextjs+azure-web-pubsub/components/room-components/frames-library/frames-library.image.tsx +48 -0
  40. package/template/+nextjs+azure-web-pubsub/components/room-components/frames-library/frames-library.presentation-image.tsx +61 -0
  41. package/template/+nextjs+azure-web-pubsub/components/room-components/frames-library/frames-library.tsx +316 -0
  42. package/template/+nextjs+azure-web-pubsub/components/room-components/frames-library/utils.ts +27 -0
  43. package/template/+nextjs+azure-web-pubsub/components/room-components/help/help-arrange.tsx +69 -0
  44. package/template/+nextjs+azure-web-pubsub/components/room-components/help/help-drawer.tsx +140 -0
  45. package/template/+nextjs+azure-web-pubsub/components/room-components/help/help-edit.tsx +80 -0
  46. package/template/+nextjs+azure-web-pubsub/components/room-components/help/help-selection.tsx +30 -0
  47. package/template/+nextjs+azure-web-pubsub/components/room-components/help/help-shortcut-element.tsx +24 -0
  48. package/template/+nextjs+azure-web-pubsub/components/room-components/help/help-tools.tsx +89 -0
  49. package/template/+nextjs+azure-web-pubsub/components/room-components/help/help-view.tsx +30 -0
  50. package/template/+nextjs+azure-web-pubsub/components/room-components/help/help-zoom.tsx +46 -0
  51. package/template/+nextjs+azure-web-pubsub/components/room-components/help/shortcut-element.tsx +42 -0
  52. package/template/+nextjs+azure-web-pubsub/components/room-components/hooks/use-context-menu.tsx +514 -0
  53. package/template/+nextjs+azure-web-pubsub/components/room-components/hooks/use-get-azure-web-pubsub-provider.ts +78 -0
  54. package/template/+nextjs+azure-web-pubsub/components/room-components/hooks/use-get-os.ts +12 -0
  55. package/template/+nextjs+azure-web-pubsub/components/room-components/hooks/use-get-weave-js-props.tsx +120 -0
  56. package/template/+nextjs+azure-web-pubsub/components/room-components/hooks/use-handle-route-params.ts +30 -0
  57. package/template/+nextjs+azure-web-pubsub/components/room-components/hooks/use-key-down.ts +29 -0
  58. package/template/+nextjs+azure-web-pubsub/components/room-components/hooks/use-keyboard-handler.tsx +557 -0
  59. package/template/+nextjs+azure-web-pubsub/components/room-components/images-library/images-library.tsx +146 -0
  60. package/template/+nextjs+azure-web-pubsub/components/room-components/inputs/input-color.tsx +101 -0
  61. package/template/+nextjs+azure-web-pubsub/components/room-components/inputs/input-font-family.tsx +99 -0
  62. package/template/+nextjs+azure-web-pubsub/components/room-components/inputs/input-number.tsx +61 -0
  63. package/template/+nextjs+azure-web-pubsub/components/room-components/inputs/input-text.tsx +51 -0
  64. package/template/+nextjs+azure-web-pubsub/components/room-components/inputs/number-input.tsx +107 -0
  65. package/template/+nextjs+azure-web-pubsub/components/room-components/node-properties/appearance-properties.tsx +119 -0
  66. package/template/+nextjs+azure-web-pubsub/components/room-components/node-properties/color-token-properties.tsx +108 -0
  67. package/template/+nextjs+azure-web-pubsub/components/room-components/node-properties/crop-properties.tsx +156 -0
  68. package/template/+nextjs+azure-web-pubsub/components/room-components/node-properties/fill-properties.tsx +115 -0
  69. package/template/+nextjs+azure-web-pubsub/components/room-components/node-properties/frame-properties.tsx +100 -0
  70. package/template/+nextjs+azure-web-pubsub/components/room-components/node-properties/image-properties.tsx +57 -0
  71. package/template/+nextjs+azure-web-pubsub/components/room-components/node-properties/position-properties.tsx +156 -0
  72. package/template/+nextjs+azure-web-pubsub/components/room-components/node-properties/size-properties.tsx +131 -0
  73. package/template/+nextjs+azure-web-pubsub/components/room-components/node-properties/stroke-properties.tsx +327 -0
  74. package/template/+nextjs+azure-web-pubsub/components/room-components/node-properties/text-properties.tsx +467 -0
  75. package/template/+nextjs+azure-web-pubsub/components/room-components/overlay/multiuse-overlay.tsx +127 -0
  76. package/template/+nextjs+azure-web-pubsub/components/room-components/overlay/node-properties.tsx +98 -0
  77. package/template/+nextjs+azure-web-pubsub/components/room-components/overlay/overlay-animation-wrapper.tsx +31 -0
  78. package/template/+nextjs+azure-web-pubsub/components/room-components/overlay/room-information-overlay.tsx +247 -0
  79. package/template/+nextjs+azure-web-pubsub/components/room-components/overlay/room-users-overlay.tsx +31 -0
  80. package/template/+nextjs+azure-web-pubsub/components/room-components/overlay/tools-overlay.tsx +289 -0
  81. package/template/+nextjs+azure-web-pubsub/components/room-components/overlay/variants.ts +58 -0
  82. package/template/+nextjs+azure-web-pubsub/components/room-components/overlay/zoom-handler-overlay.tsx +447 -0
  83. package/template/+nextjs+azure-web-pubsub/components/room-components/room-error.tsx +37 -0
  84. package/template/+nextjs+azure-web-pubsub/components/room-components/room-loader/room-loader.tsx +98 -0
  85. package/template/+nextjs+azure-web-pubsub/components/room-components/selection-information.tsx +74 -0
  86. package/template/+nextjs+azure-web-pubsub/components/room-components/toggle-icon-button.tsx +60 -0
  87. package/template/+nextjs+azure-web-pubsub/components/room-components/toolbar/toolbar-button.tsx +60 -0
  88. package/template/+nextjs+azure-web-pubsub/components/room-components/toolbar/toolbar-toggle-button.tsx +40 -0
  89. package/template/+nextjs+azure-web-pubsub/components/room-components/toolbar/toolbar.tsx +28 -0
  90. package/template/+nextjs+azure-web-pubsub/components/room-components/upload-file.tsx +130 -0
  91. package/template/+nextjs+azure-web-pubsub/components/room-components/with-instance-node.tsx +53 -0
  92. package/template/+nextjs+azure-web-pubsub/components/ui/accordion.tsx +66 -0
  93. package/template/+nextjs+azure-web-pubsub/components/ui/avatar.tsx +53 -0
  94. package/template/+nextjs+azure-web-pubsub/components/ui/button.tsx +58 -0
  95. package/template/+nextjs+azure-web-pubsub/components/ui/card.tsx +68 -0
  96. package/template/+nextjs+azure-web-pubsub/components/ui/checkbox.tsx +32 -0
  97. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/color-picker-component.tsx +69 -0
  98. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/context/color-picker-context.tsx +28 -0
  99. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/editor/color-picker-format-editor.tsx +34 -0
  100. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/index.ts +7 -0
  101. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/selector/color-picker-alpha.tsx +79 -0
  102. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/selector/color-picker-eyedropper.tsx +95 -0
  103. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/selector/color-picker-format-selector.tsx +50 -0
  104. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/selector/color-picker-hue.tsx +67 -0
  105. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/selector/color-picker-saturation.tsx +145 -0
  106. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/text-inputs/color-picker-alpha-percentage.tsx +60 -0
  107. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/text-inputs/color-picker-hexa.tsx +65 -0
  108. package/template/+nextjs+azure-web-pubsub/components/ui/color-picker/text-inputs/color-picker-rgba.tsx +62 -0
  109. package/template/+nextjs+azure-web-pubsub/components/ui/command.tsx +177 -0
  110. package/template/+nextjs+azure-web-pubsub/components/ui/dialog.tsx +135 -0
  111. package/template/+nextjs+azure-web-pubsub/components/ui/drawer.tsx +132 -0
  112. package/template/+nextjs+azure-web-pubsub/components/ui/dropdown-menu.tsx +201 -0
  113. package/template/+nextjs+azure-web-pubsub/components/ui/form.tsx +167 -0
  114. package/template/+nextjs+azure-web-pubsub/components/ui/input.tsx +21 -0
  115. package/template/+nextjs+azure-web-pubsub/components/ui/label.tsx +24 -0
  116. package/template/+nextjs+azure-web-pubsub/components/ui/popover.tsx +48 -0
  117. package/template/+nextjs+azure-web-pubsub/components/ui/reactbits/Backgrounds/Dither/Dither.tsx +350 -0
  118. package/template/+nextjs+azure-web-pubsub/components/ui/reactbits/Backgrounds/Threads/Threads.tsx +239 -0
  119. package/template/+nextjs+azure-web-pubsub/components/ui/reactbits/TextAnimations/RotatingText/RotatingText.tsx +276 -0
  120. package/template/+nextjs+azure-web-pubsub/components/ui/scroll-area.tsx +58 -0
  121. package/template/+nextjs+azure-web-pubsub/components/ui/select.tsx +185 -0
  122. package/template/+nextjs+azure-web-pubsub/components/ui/sheet.tsx +139 -0
  123. package/template/+nextjs+azure-web-pubsub/components/ui/sonner.tsx +25 -0
  124. package/template/+nextjs+azure-web-pubsub/components/ui/tabs.tsx +66 -0
  125. package/template/+nextjs+azure-web-pubsub/components/ui/tooltip.tsx +61 -0
  126. package/template/+nextjs+azure-web-pubsub/components/utils/constants.ts +118 -0
  127. package/template/+nextjs+azure-web-pubsub/components/utils/logo.tsx +34 -0
  128. package/template/+nextjs+azure-web-pubsub/components.json +21 -0
  129. package/template/+nextjs+azure-web-pubsub/example.env +2 -0
  130. package/template/+nextjs+azure-web-pubsub/example.gitignore +44 -0
  131. package/template/+nextjs+azure-web-pubsub/jsrepo.json +11 -0
  132. package/template/+nextjs+azure-web-pubsub/lib/utils.ts +43 -0
  133. package/template/+nextjs+azure-web-pubsub/new-types.d.ts +8 -0
  134. package/template/+nextjs+azure-web-pubsub/next-env.d.ts +5 -0
  135. package/template/+nextjs+azure-web-pubsub/next.config.js +52 -0
  136. package/template/+nextjs+azure-web-pubsub/postcss.config.mjs +5 -0
  137. package/template/+nextjs+azure-web-pubsub/store/store.ts +241 -0
  138. package/template/+nextjs+azure-web-pubsub/tsconfig.json +37 -0
  139. package/template/+nextjs+azure-web-pubsub/vitest.config.mts +10 -0
  140. package/template/+nextjs+websockets/README.md +39 -0
  141. package/template/+nextjs+websockets/api/del-image.ts +8 -0
  142. package/template/+nextjs+websockets/api/get-images.ts +15 -0
  143. package/template/+nextjs+websockets/api/post-image.ts +14 -0
  144. package/template/+nextjs+websockets/api/post-remove-background.ts +10 -0
  145. package/template/+nextjs+websockets/app/error/page.tsx +10 -0
  146. package/template/+nextjs+websockets/app/favicon.ico +0 -0
  147. package/template/+nextjs+websockets/app/globals.css +193 -0
  148. package/template/+nextjs+websockets/app/layout.tsx +46 -0
  149. package/template/+nextjs+websockets/app/page.tsx +7 -0
  150. package/template/+nextjs+websockets/app/providers.tsx +18 -0
  151. package/template/+nextjs+websockets/app/room/[roomId]/page.tsx +5 -0
  152. package/template/+nextjs+websockets/assets/images/home.png +0 -0
  153. package/template/+nextjs+websockets/assets/images/logo.png +0 -0
  154. package/template/+nextjs+websockets/components/actions/align-elements-tool/align-elements-tool.ts +94 -0
  155. package/template/+nextjs+websockets/components/actions/color-token-tool/color-token-tool.ts +164 -0
  156. package/template/+nextjs+websockets/components/actions/color-token-tool/constants.ts +5 -0
  157. package/template/+nextjs+websockets/components/actions/color-token-tool/types.ts +12 -0
  158. package/template/+nextjs+websockets/components/error/error.tsx +62 -0
  159. package/template/+nextjs+websockets/components/error/errors.ts +35 -0
  160. package/template/+nextjs+websockets/components/home/home.tsx +92 -0
  161. package/template/+nextjs+websockets/components/home-components/home-showcase-animation.tsx +119 -0
  162. package/template/+nextjs+websockets/components/home-components/login-form.tsx +117 -0
  163. package/template/+nextjs+websockets/components/nodes/color-token/color-token.ts +171 -0
  164. package/template/+nextjs+websockets/components/room/room.layout.tsx +115 -0
  165. package/template/+nextjs+websockets/components/room/room.tsx +125 -0
  166. package/template/+nextjs+websockets/components/room-components/color-tokens-library/color-token.tsx +31 -0
  167. package/template/+nextjs+websockets/components/room-components/color-tokens-library/color-tokens-library.tsx +64 -0
  168. package/template/+nextjs+websockets/components/room-components/connected-users.tsx +152 -0
  169. package/template/+nextjs+websockets/components/room-components/connection-status.tsx +52 -0
  170. package/template/+nextjs+websockets/components/room-components/context-menu.tsx +152 -0
  171. package/template/+nextjs+websockets/components/room-components/frames-library/frames-library.image.tsx +48 -0
  172. package/template/+nextjs+websockets/components/room-components/frames-library/frames-library.presentation-image.tsx +61 -0
  173. package/template/+nextjs+websockets/components/room-components/frames-library/frames-library.tsx +316 -0
  174. package/template/+nextjs+websockets/components/room-components/frames-library/utils.ts +27 -0
  175. package/template/+nextjs+websockets/components/room-components/help/help-arrange.tsx +69 -0
  176. package/template/+nextjs+websockets/components/room-components/help/help-drawer.tsx +140 -0
  177. package/template/+nextjs+websockets/components/room-components/help/help-edit.tsx +80 -0
  178. package/template/+nextjs+websockets/components/room-components/help/help-selection.tsx +30 -0
  179. package/template/+nextjs+websockets/components/room-components/help/help-shortcut-element.tsx +24 -0
  180. package/template/+nextjs+websockets/components/room-components/help/help-tools.tsx +89 -0
  181. package/template/+nextjs+websockets/components/room-components/help/help-view.tsx +30 -0
  182. package/template/+nextjs+websockets/components/room-components/help/help-zoom.tsx +46 -0
  183. package/template/+nextjs+websockets/components/room-components/help/shortcut-element.tsx +42 -0
  184. package/template/+nextjs+websockets/components/room-components/hooks/use-context-menu.tsx +514 -0
  185. package/template/+nextjs+websockets/components/room-components/hooks/use-get-os.ts +12 -0
  186. package/template/+nextjs+websockets/components/room-components/hooks/use-get-weave-js-props.tsx +120 -0
  187. package/template/+nextjs+websockets/components/room-components/hooks/use-get-websockets-provider.ts +79 -0
  188. package/template/+nextjs+websockets/components/room-components/hooks/use-handle-route-params.ts +30 -0
  189. package/template/+nextjs+websockets/components/room-components/hooks/use-key-down.ts +29 -0
  190. package/template/+nextjs+websockets/components/room-components/hooks/use-keyboard-handler.tsx +557 -0
  191. package/template/+nextjs+websockets/components/room-components/images-library/images-library.tsx +146 -0
  192. package/template/+nextjs+websockets/components/room-components/inputs/input-color.tsx +101 -0
  193. package/template/+nextjs+websockets/components/room-components/inputs/input-font-family.tsx +99 -0
  194. package/template/+nextjs+websockets/components/room-components/inputs/input-number.tsx +61 -0
  195. package/template/+nextjs+websockets/components/room-components/inputs/input-text.tsx +51 -0
  196. package/template/+nextjs+websockets/components/room-components/inputs/number-input.tsx +107 -0
  197. package/template/+nextjs+websockets/components/room-components/node-properties/appearance-properties.tsx +119 -0
  198. package/template/+nextjs+websockets/components/room-components/node-properties/color-token-properties.tsx +108 -0
  199. package/template/+nextjs+websockets/components/room-components/node-properties/crop-properties.tsx +156 -0
  200. package/template/+nextjs+websockets/components/room-components/node-properties/fill-properties.tsx +115 -0
  201. package/template/+nextjs+websockets/components/room-components/node-properties/frame-properties.tsx +100 -0
  202. package/template/+nextjs+websockets/components/room-components/node-properties/image-properties.tsx +57 -0
  203. package/template/+nextjs+websockets/components/room-components/node-properties/position-properties.tsx +156 -0
  204. package/template/+nextjs+websockets/components/room-components/node-properties/size-properties.tsx +131 -0
  205. package/template/+nextjs+websockets/components/room-components/node-properties/stroke-properties.tsx +327 -0
  206. package/template/+nextjs+websockets/components/room-components/node-properties/text-properties.tsx +467 -0
  207. package/template/+nextjs+websockets/components/room-components/overlay/multiuse-overlay.tsx +127 -0
  208. package/template/+nextjs+websockets/components/room-components/overlay/node-properties.tsx +98 -0
  209. package/template/+nextjs+websockets/components/room-components/overlay/overlay-animation-wrapper.tsx +31 -0
  210. package/template/+nextjs+websockets/components/room-components/overlay/room-information-overlay.tsx +247 -0
  211. package/template/+nextjs+websockets/components/room-components/overlay/room-users-overlay.tsx +31 -0
  212. package/template/+nextjs+websockets/components/room-components/overlay/tools-overlay.tsx +289 -0
  213. package/template/+nextjs+websockets/components/room-components/overlay/variants.ts +58 -0
  214. package/template/+nextjs+websockets/components/room-components/overlay/zoom-handler-overlay.tsx +447 -0
  215. package/template/+nextjs+websockets/components/room-components/room-error.tsx +37 -0
  216. package/template/+nextjs+websockets/components/room-components/room-loader/room-loader.tsx +98 -0
  217. package/template/+nextjs+websockets/components/room-components/selection-information.tsx +74 -0
  218. package/template/+nextjs+websockets/components/room-components/toggle-icon-button.tsx +60 -0
  219. package/template/+nextjs+websockets/components/room-components/toolbar/toolbar-button.tsx +60 -0
  220. package/template/+nextjs+websockets/components/room-components/toolbar/toolbar-toggle-button.tsx +40 -0
  221. package/template/+nextjs+websockets/components/room-components/toolbar/toolbar.tsx +28 -0
  222. package/template/+nextjs+websockets/components/room-components/upload-file.tsx +130 -0
  223. package/template/+nextjs+websockets/components/room-components/with-instance-node.tsx +53 -0
  224. package/template/+nextjs+websockets/components/ui/accordion.tsx +66 -0
  225. package/template/+nextjs+websockets/components/ui/avatar.tsx +53 -0
  226. package/template/+nextjs+websockets/components/ui/button.tsx +58 -0
  227. package/template/+nextjs+websockets/components/ui/card.tsx +68 -0
  228. package/template/+nextjs+websockets/components/ui/checkbox.tsx +32 -0
  229. package/template/+nextjs+websockets/components/ui/color-picker/color-picker-component.tsx +69 -0
  230. package/template/+nextjs+websockets/components/ui/color-picker/context/color-picker-context.tsx +28 -0
  231. package/template/+nextjs+websockets/components/ui/color-picker/editor/color-picker-format-editor.tsx +34 -0
  232. package/template/+nextjs+websockets/components/ui/color-picker/index.ts +7 -0
  233. package/template/+nextjs+websockets/components/ui/color-picker/selector/color-picker-alpha.tsx +79 -0
  234. package/template/+nextjs+websockets/components/ui/color-picker/selector/color-picker-eyedropper.tsx +95 -0
  235. package/template/+nextjs+websockets/components/ui/color-picker/selector/color-picker-format-selector.tsx +50 -0
  236. package/template/+nextjs+websockets/components/ui/color-picker/selector/color-picker-hue.tsx +67 -0
  237. package/template/+nextjs+websockets/components/ui/color-picker/selector/color-picker-saturation.tsx +145 -0
  238. package/template/+nextjs+websockets/components/ui/color-picker/text-inputs/color-picker-alpha-percentage.tsx +60 -0
  239. package/template/+nextjs+websockets/components/ui/color-picker/text-inputs/color-picker-hexa.tsx +65 -0
  240. package/template/+nextjs+websockets/components/ui/color-picker/text-inputs/color-picker-rgba.tsx +62 -0
  241. package/template/+nextjs+websockets/components/ui/command.tsx +177 -0
  242. package/template/+nextjs+websockets/components/ui/dialog.tsx +135 -0
  243. package/template/+nextjs+websockets/components/ui/drawer.tsx +132 -0
  244. package/template/+nextjs+websockets/components/ui/dropdown-menu.tsx +201 -0
  245. package/template/+nextjs+websockets/components/ui/form.tsx +167 -0
  246. package/template/+nextjs+websockets/components/ui/input.tsx +21 -0
  247. package/template/+nextjs+websockets/components/ui/label.tsx +24 -0
  248. package/template/+nextjs+websockets/components/ui/popover.tsx +48 -0
  249. package/template/+nextjs+websockets/components/ui/reactbits/Backgrounds/Dither/Dither.tsx +350 -0
  250. package/template/+nextjs+websockets/components/ui/reactbits/Backgrounds/Threads/Threads.tsx +239 -0
  251. package/template/+nextjs+websockets/components/ui/reactbits/TextAnimations/RotatingText/RotatingText.tsx +276 -0
  252. package/template/+nextjs+websockets/components/ui/scroll-area.tsx +58 -0
  253. package/template/+nextjs+websockets/components/ui/select.tsx +185 -0
  254. package/template/+nextjs+websockets/components/ui/sheet.tsx +139 -0
  255. package/template/+nextjs+websockets/components/ui/sonner.tsx +25 -0
  256. package/template/+nextjs+websockets/components/ui/tabs.tsx +66 -0
  257. package/template/+nextjs+websockets/components/ui/tooltip.tsx +61 -0
  258. package/template/+nextjs+websockets/components/utils/constants.ts +118 -0
  259. package/template/+nextjs+websockets/components/utils/logo.tsx +34 -0
  260. package/template/+nextjs+websockets/components.json +21 -0
  261. package/template/+nextjs+websockets/example.env +2 -0
  262. package/template/+nextjs+websockets/example.gitignore +44 -0
  263. package/template/+nextjs+websockets/jsrepo.json +11 -0
  264. package/template/+nextjs+websockets/lib/utils.ts +43 -0
  265. package/template/+nextjs+websockets/new-types.d.ts +8 -0
  266. package/template/+nextjs+websockets/next-env.d.ts +5 -0
  267. package/template/+nextjs+websockets/next.config.js +52 -0
  268. package/template/+nextjs+websockets/postcss.config.mjs +5 -0
  269. package/template/+nextjs+websockets/store/store.ts +241 -0
  270. package/template/+nextjs+websockets/tsconfig.json +37 -0
  271. package/template/+nextjs+websockets/vitest.config.mts +10 -0
  272. package/template/package.json +81 -0
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import {
5
+ Cloud,
6
+ //CloudCog,
7
+ CloudAlert,
8
+ } from 'lucide-react';
9
+ import { WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS } from '@inditextech/weave-store-azure-web-pubsub/client';
10
+ import { cn } from '@/lib/utils';
11
+
12
+ type ConnectionStatusProps = {
13
+ weaveConnectionStatus: string;
14
+ };
15
+
16
+ export const ConnectionStatus = ({
17
+ weaveConnectionStatus,
18
+ }: Readonly<ConnectionStatusProps>) => {
19
+ return (
20
+ <div className="flex">
21
+ <div
22
+ className={cn(
23
+ 'bg-light-background-1 p-2 flex justify-center items-center rounded-full',
24
+ {
25
+ ['bg-emerald-200 text-black']:
26
+ weaveConnectionStatus ===
27
+ WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.CONNECTED,
28
+ // ["bg-sky-300 text-white"]:
29
+ // weaveConnectionStatus ===
30
+ // WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.CONNECTING,
31
+ ['bg-rose-300 text-white']:
32
+ weaveConnectionStatus ===
33
+ WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.DISCONNECTED,
34
+ }
35
+ )}
36
+ >
37
+ {weaveConnectionStatus ===
38
+ WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.CONNECTED && (
39
+ <Cloud size={20} />
40
+ )}
41
+ {/* {weaveConnectionStatus ===
42
+ WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.CONNECTING && (
43
+ <CloudCog size={20} />
44
+ )} */}
45
+ {weaveConnectionStatus ===
46
+ WEAVE_STORE_AZURE_WEB_PUBSUB_CONNECTION_STATUS.DISCONNECTED && (
47
+ <CloudAlert size={20} />
48
+ )}
49
+ </div>
50
+ </div>
51
+ );
52
+ };
@@ -0,0 +1,152 @@
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ type ContextMenuButtonProps = {
7
+ label: React.ReactNode;
8
+ icon?: React.ReactNode;
9
+ disabled?: boolean;
10
+ onClick: () => void;
11
+ };
12
+
13
+ export type ContextMenuOption = {
14
+ id: string;
15
+ type: "button" | "divider";
16
+ } & (
17
+ | {
18
+ type: "button";
19
+ label: string | React.ReactNode;
20
+ icon?: React.ReactNode;
21
+ disabled?: boolean;
22
+ onClick: () => void;
23
+ }
24
+ | {
25
+ type: "divider";
26
+ }
27
+ );
28
+
29
+ type ContextMenuProps = {
30
+ show: boolean;
31
+ onChanged: (show: boolean) => void;
32
+ position: { x: number; y: number };
33
+ options: ContextMenuOption[];
34
+ };
35
+
36
+ function ContextMenuButton({
37
+ label,
38
+ icon,
39
+ disabled,
40
+ onClick,
41
+ }: Readonly<ContextMenuButtonProps>) {
42
+ return (
43
+ <button
44
+ className={cn(
45
+ "!cursor-pointer w-[calc(100%-8px)] flex justify-between items-center gap-2 font-noto-sans-mono text-sm text-left whitespace-nowrap m-1 text-foreground px-2 py-1.5",
46
+ {
47
+ ["hover:bg-accent"]: !disabled,
48
+ ["!cursor-default hover:bg-white text-muted-foreground"]: disabled,
49
+ }
50
+ )}
51
+ disabled={disabled}
52
+ onClick={onClick}
53
+ >
54
+ {icon} <div className="w-full">{label}</div>
55
+ </button>
56
+ );
57
+ }
58
+
59
+ export const ContextMenuRender = ({
60
+ show,
61
+ onChanged,
62
+ position,
63
+ options,
64
+ }: Readonly<ContextMenuProps>) => {
65
+ const ref = React.useRef<HTMLDivElement>(null);
66
+
67
+ React.useEffect(() => {
68
+ if (ref.current && show) {
69
+ const boundingRect = ref.current.getBoundingClientRect();
70
+ let X = boundingRect.x;
71
+ let Y = boundingRect.y;
72
+
73
+ X = Math.max(
74
+ 20,
75
+ Math.min(X, window.innerWidth - boundingRect.width - 20)
76
+ );
77
+ Y = Math.max(
78
+ 20,
79
+ Math.min(Y, window.innerHeight - boundingRect.height - 20)
80
+ );
81
+
82
+ ref.current.style.top = `${Y}px`;
83
+ ref.current.style.left = `${X}px`;
84
+ }
85
+ }, [show]);
86
+
87
+ React.useEffect(() => {
88
+ function checkIfClickedOutside(e: MouseEvent) {
89
+ if (
90
+ ref.current &&
91
+ e.target !== ref.current &&
92
+ !ref.current.contains(e.target as Node)
93
+ ) {
94
+ ref.current.style.display = `none`;
95
+ onChanged(false);
96
+ }
97
+ }
98
+
99
+ function checkIfTouchOutside(e: TouchEvent) {
100
+ console.log(e);
101
+ if (
102
+ ref.current &&
103
+ e.target !== ref.current &&
104
+ !ref.current.contains(e.target as Node)
105
+ ) {
106
+ ref.current.style.display = `none`;
107
+ onChanged(false);
108
+ }
109
+ }
110
+
111
+ window.addEventListener("click", checkIfClickedOutside);
112
+ window.addEventListener("touchstart", checkIfTouchOutside);
113
+
114
+ return () => {
115
+ window.removeEventListener("click", checkIfClickedOutside);
116
+ window.removeEventListener("touchstart", checkIfTouchOutside);
117
+ };
118
+ // eslint-disable-next-line react-hooks/exhaustive-deps
119
+ }, []);
120
+
121
+ return (
122
+ <div
123
+ ref={ref}
124
+ className="fixed w-[300px] bg-white flex flex-col border border-zinc-200 shadow-lg"
125
+ style={{
126
+ display: show ? "block" : "none",
127
+ top: `${position.y}px`,
128
+ left: `${position.x}px`,
129
+ zIndex: 10,
130
+ }}
131
+ >
132
+ {options.map((option) => {
133
+ if (option.type === "button") {
134
+ return (
135
+ <ContextMenuButton
136
+ key={option.id}
137
+ label={option.label}
138
+ icon={option.icon}
139
+ disabled={option.disabled ?? false}
140
+ onClick={option.onClick}
141
+ />
142
+ );
143
+ }
144
+ if (option.type === "divider") {
145
+ return (
146
+ <div key={option.id} className="w-full h-[1px] bg-accent"></div>
147
+ );
148
+ }
149
+ })}
150
+ </div>
151
+ );
152
+ };
@@ -0,0 +1,48 @@
1
+ import React from "react";
2
+ import Image from "next/image";
3
+ import Konva from "konva";
4
+ import { toImageAsync } from "./utils";
5
+
6
+ type FrameImageProps = {
7
+ node: Konva.Group;
8
+ };
9
+
10
+ export const FrameImage = ({ node }: Readonly<FrameImageProps>) => {
11
+ const [image, setImage] = React.useState<React.ReactElement | null>(null);
12
+
13
+ React.useEffect(() => {
14
+ setInterval(async () => {
15
+ const nodeAttrs = node.getAttrs();
16
+ try {
17
+ // const box = frameInternal.getClientRect({ relativeTo: stage });
18
+ const frameBg = node.findOne(`#${nodeAttrs.id}-bg`) as Konva.Group;
19
+ if (!frameBg) {
20
+ return;
21
+ }
22
+ const boxBg = frameBg.getClientRect();
23
+ const img = await toImageAsync(node, {
24
+ x: boxBg.x + 1,
25
+ y: boxBg.y + 1,
26
+ width: boxBg.width - 2,
27
+ height: boxBg.height - 2,
28
+ });
29
+ setImage(
30
+ <Image
31
+ src={img.src}
32
+ width={284}
33
+ height={201}
34
+ alt="A frame image"
35
+ className="object-fit w-full h-full"
36
+ />
37
+ );
38
+ } catch (ex) {
39
+ console.error(ex);
40
+ }
41
+ }, 100);
42
+ // eslint-disable-next-line react-hooks/exhaustive-deps
43
+ }, []);
44
+
45
+ return (
46
+ <div className="w-full aspect-video border border-zinc-200">{image}</div>
47
+ );
48
+ };
@@ -0,0 +1,61 @@
1
+ import React from "react";
2
+ import Image from "next/image";
3
+ import Konva from "konva";
4
+ import { toImageAsync } from "./utils";
5
+
6
+ type FrameImageProps = {
7
+ node: Konva.Group;
8
+ };
9
+
10
+ export const FramePresentationImage = ({ node }: Readonly<FrameImageProps>) => {
11
+ const [loading, setLoading] = React.useState<boolean>(false);
12
+ const [image, setImage] = React.useState<React.ReactElement | null>(null);
13
+
14
+ React.useEffect(() => {
15
+ async function loadPresentationImage() {
16
+ const nodeAttrs = node.getAttrs();
17
+ try {
18
+ // const box = frameInternal.getClientRect({ relativeTo: stage });
19
+ const frameBg = node.findOne(`#${nodeAttrs.id}-bg`) as Konva.Group;
20
+ if (!frameBg) {
21
+ return;
22
+ }
23
+ const boxBg = frameBg.getClientRect();
24
+ setLoading(true);
25
+ const img = await toImageAsync(node, {
26
+ pixelRatio: 6,
27
+ x: boxBg.x + 2,
28
+ y: boxBg.y + 2,
29
+ width: boxBg.width - 4,
30
+ height: boxBg.height - 4,
31
+ });
32
+ setLoading(false);
33
+ setImage(
34
+ <Image
35
+ src={img.src}
36
+ width={500}
37
+ height={600}
38
+ alt="A frame image"
39
+ className="object-contain w-full h-full"
40
+ />
41
+ );
42
+ } catch (ex) {
43
+ console.error(ex);
44
+ }
45
+ }
46
+ loadPresentationImage();
47
+ // eslint-disable-next-line react-hooks/exhaustive-deps
48
+ }, []);
49
+
50
+ if (loading) {
51
+ return (
52
+ <div className="w-full h-full flex justify-center items-center">
53
+ <div className="font-noto-sans-mono text-2xl text-white">
54
+ Loading...
55
+ </div>
56
+ </div>
57
+ );
58
+ }
59
+
60
+ return image;
61
+ };
@@ -0,0 +1,316 @@
1
+ import { PDFDocument } from 'pdf-lib';
2
+ import { WeaveSelection, WeaveStateElement } from '@inditextech/weave-types';
3
+ import React from 'react';
4
+ import Konva from 'konva';
5
+ import { Checkbox } from '@/components/ui/checkbox';
6
+ import { useCollaborationRoom } from '@/store/store';
7
+ import { useWeave } from '@inditextech/weave-react';
8
+ import {
9
+ AlignStartHorizontal,
10
+ Download,
11
+ Presentation,
12
+ SkipBack,
13
+ SkipForward,
14
+ SquareCheck,
15
+ StepBack,
16
+ StepForward,
17
+ XIcon,
18
+ } from 'lucide-react';
19
+ import { toImageAsync } from './utils';
20
+ import { FrameImage } from './frames-library.image';
21
+ import { FramePresentationImage } from './frames-library.presentation-image';
22
+
23
+ export const FramesLibrary = () => {
24
+ const instance = useWeave((state) => state.instance);
25
+ const appState = useWeave((state) => state.appState);
26
+ const selectedNodes = useWeave((state) => state.selection.nodes);
27
+
28
+ const [presentationMode, setPresentationMode] =
29
+ React.useState<boolean>(false);
30
+ const [actualFrame, setActualFrame] = React.useState<number>(0);
31
+ const [selectedFrames, setSelectedFrames] = React.useState<string[]>([]);
32
+
33
+ const framesLibraryVisible = useCollaborationRoom(
34
+ (state) => state.frames.library.visible
35
+ );
36
+
37
+ const framesAvailable = React.useMemo(() => {
38
+ if (!instance) {
39
+ return [];
40
+ }
41
+
42
+ const stage = instance.getStage();
43
+ const nodes = instance.findNodesByType(
44
+ appState.weave as WeaveStateElement,
45
+ 'frame'
46
+ );
47
+
48
+ const frames: Konva.Node[] = [];
49
+ for (const node of nodes) {
50
+ const ele = stage.findOne(`#${node.key}`);
51
+ if (ele) {
52
+ frames.push(ele);
53
+ }
54
+ }
55
+ return frames;
56
+ }, [instance, appState]);
57
+
58
+ const selectedNodesAllFrame = React.useMemo(() => {
59
+ let allFrame = true;
60
+ for (const node of selectedNodes) {
61
+ if (node.node.type !== 'frame') {
62
+ allFrame = false;
63
+ break;
64
+ }
65
+ }
66
+ return allFrame;
67
+ }, [selectedNodes]);
68
+
69
+ const alignItemsHandler = React.useCallback(() => {
70
+ if (!instance) {
71
+ return;
72
+ }
73
+
74
+ instance.triggerAction<{ gap: number; nodes: WeaveSelection[] }>(
75
+ 'alignElementsTool',
76
+ {
77
+ gap: 20,
78
+ nodes: selectedNodes,
79
+ }
80
+ );
81
+ }, [instance, selectedNodes]);
82
+
83
+ const exportFramesHandler = React.useCallback(async () => {
84
+ if (!instance) {
85
+ return;
86
+ }
87
+
88
+ const stage = instance.getStage();
89
+
90
+ let framesToRender = selectedFrames;
91
+ if (framesToRender.length === 0) {
92
+ framesToRender = framesAvailable.map((e) => e.getAttrs().id ?? '');
93
+ }
94
+
95
+ const pages: { title: string; image: string }[] = [];
96
+ for (const frameId of selectedFrames) {
97
+ const node = stage.findOne(`#${frameId}`) as Konva.Group | undefined;
98
+ if (node) {
99
+ const attrs = node.getAttrs();
100
+ const frameBg = node.findOne(`#${attrs.id}-bg`) as Konva.Group;
101
+ const boxBg = frameBg.getClientRect();
102
+ const img = await toImageAsync(node, {
103
+ x: boxBg.x + 2,
104
+ y: boxBg.y + 2,
105
+ width: boxBg.width - 4,
106
+ height: boxBg.height - 4,
107
+ });
108
+ pages.push({ title: attrs.title, image: img.src });
109
+ }
110
+ }
111
+
112
+ const pdfDoc = await PDFDocument.create();
113
+ for (const page of pages) {
114
+ const pdfPage = pdfDoc.addPage([1403, 992]);
115
+ const imageDoc = await pdfDoc.embedJpg(page.image);
116
+ pdfPage.drawImage(imageDoc, {
117
+ x: 30,
118
+ y: 30,
119
+ width: 1403 - 60,
120
+ height: 992 - 60,
121
+ });
122
+ }
123
+
124
+ const pdfDataUri = await pdfDoc.saveAsBase64({ dataUri: true });
125
+
126
+ const link = document.createElement('a');
127
+ link.href = pdfDataUri;
128
+ link.download = 'test.pdf';
129
+ link.click();
130
+ }, [instance, selectedFrames, framesAvailable]);
131
+
132
+ const actualNodePresentation = React.useMemo(() => {
133
+ const frameId = selectedFrames[actualFrame];
134
+ const node = framesAvailable.find((e) => e.getAttrs().id === frameId);
135
+ if (node) {
136
+ return node;
137
+ }
138
+ return undefined;
139
+ }, [actualFrame, selectedFrames, framesAvailable]);
140
+
141
+ if (!instance) {
142
+ return null;
143
+ }
144
+
145
+ if (!framesLibraryVisible) {
146
+ return null;
147
+ }
148
+
149
+ return (
150
+ <>
151
+ <div className="pointer-events-auto w-full h-full">
152
+ <div className="w-[calc(100%-38px)] font-title-xs p-1 pr-0 bg-white flex justify-between items-center">
153
+ <div className="flex justify-between font-noto-sans-mono font-light items-center text-md pl-2">
154
+ Frames
155
+ </div>
156
+ <div className="flex justify-end items-center gap-1">
157
+ <button
158
+ className="group cursor-pointer bg-transparent disabled:cursor-default hover:disabled:bg-transparent hover:bg-accent p-2"
159
+ disabled={selectedFrames.length === 0}
160
+ onClick={() => {
161
+ setActualFrame(0);
162
+ setPresentationMode((prev) => !prev);
163
+ }}
164
+ >
165
+ <Presentation className="group-disabled:text-accent" size={16} />
166
+ </button>
167
+ <button
168
+ className="cursor-pointer bg-transparent hover:bg-accent p-2"
169
+ disabled={selectedNodes.length <= 1 || !selectedNodesAllFrame}
170
+ onClick={alignItemsHandler}
171
+ >
172
+ <AlignStartHorizontal size={16} />
173
+ </button>
174
+ <button
175
+ className="cursor-pointer bg-transparent hover:bg-accent p-2"
176
+ onClick={() => {
177
+ if (selectedFrames.length === 0) {
178
+ const frames = framesAvailable.map((frame) => {
179
+ const attrs = frame.getAttrs();
180
+ return attrs.id ?? '';
181
+ });
182
+ setSelectedFrames(frames);
183
+ } else {
184
+ setSelectedFrames([]);
185
+ }
186
+ }}
187
+ >
188
+ <SquareCheck size={16} />
189
+ </button>
190
+ <button
191
+ className="group cursor-pointer bg-transparent disabled:cursor-default hover:disabled:bg-transparent hover:bg-accent p-2"
192
+ disabled={selectedFrames.length === 0}
193
+ onClick={exportFramesHandler}
194
+ >
195
+ <Download className="group-disabled:text-accent" size={16} />
196
+ </button>
197
+ </div>
198
+ </div>
199
+ <div className="flex flex-col gap-2 w-full h-[calc(100%-50px)] border-t border-zinc-200 p-3">
200
+ {framesAvailable.length === 0 && (
201
+ <div className="col-span-2 w-full flex flex-col justify-center items-center text-sm py-5 text-center">
202
+ <b>No frames created</b>
203
+ <span className="text-xs">Add a frame to the whiteboard</span>
204
+ </div>
205
+ )}
206
+ {framesAvailable.map((node) => {
207
+ const attrs = node.getAttrs();
208
+
209
+ return (
210
+ <div
211
+ key={attrs.id}
212
+ className="w-full bg-light-background-1 flex flex-col gap-2"
213
+ >
214
+ <div className="w-full flex justify-between items-center">
215
+ <div className="w-full text-xs font-noto-sans-mono font-light">
216
+ {attrs.title}
217
+ </div>
218
+ <div className="font-label-l-regular">
219
+ <Checkbox
220
+ className="cursor-pointer"
221
+ checked={
222
+ selectedFrames.findIndex((e) => e === attrs.id) !== -1
223
+ }
224
+ onCheckedChange={() => {
225
+ setSelectedFrames((prev) => {
226
+ const newElements = new Set(prev);
227
+ if (newElements.has(attrs.id ?? '')) {
228
+ newElements.delete(attrs.id ?? '');
229
+ } else {
230
+ newElements.add(attrs.id ?? '');
231
+ }
232
+ return Array.from(newElements);
233
+ });
234
+ }}
235
+ />
236
+ </div>
237
+ </div>
238
+ <FrameImage node={node as Konva.Group} />
239
+ </div>
240
+ );
241
+ })}
242
+ </div>
243
+ </div>
244
+ {presentationMode && (
245
+ <div className="fixed top-0 left-0 right-0 bottom-0 bg-black flex flex-col gap-3 justify-center items-start">
246
+ <div className="absolute top-8 right-8 flex justify-end items-center p-1">
247
+ <div className="flex justify-end items-center shadow-lg bg-white">
248
+ <button
249
+ className="cursor-pointer bg-transparent hover:bg-accent p-2"
250
+ onClick={() => {
251
+ setPresentationMode((prev) => !prev);
252
+ }}
253
+ >
254
+ <XIcon size={24} />
255
+ </button>
256
+ </div>
257
+ </div>
258
+ <div className="absolute bottom-8 left-8 right-8 flex justify-center items-center">
259
+ <div className="flex justify-center items-center p-1">
260
+ <div className="flex justify-end items-center shadow-lg bg-white border border-zinc-200 p-1">
261
+ <button
262
+ className="group cursor-pointer bg-transparent disabled:cursor-default hover:disabled:bg-transparent hover:bg-accent p-2"
263
+ disabled={actualFrame === 0}
264
+ onClick={() => {
265
+ setActualFrame(0);
266
+ }}
267
+ >
268
+ <SkipBack className="group-disabled:text-accent" size={24} />
269
+ </button>
270
+ <button
271
+ className="group cursor-pointer bg-transparent disabled:cursor-default hover:disabled:bg-transparent hover:bg-accent p-2"
272
+ disabled={actualFrame === 0}
273
+ onClick={() => {
274
+ setActualFrame((prev) => prev - 1);
275
+ }}
276
+ >
277
+ <StepBack className="group-disabled:text-accent" size={24} />
278
+ </button>
279
+ <button
280
+ className="group cursor-pointer bg-transparent disabled:cursor-default hover:disabled:bg-transparent hover:bg-accent p-2"
281
+ disabled={actualFrame === selectedFrames.length - 1}
282
+ onClick={() => {
283
+ setActualFrame((prev) => prev + 1);
284
+ }}
285
+ >
286
+ <StepForward
287
+ className="group-disabled:text-accent"
288
+ size={24}
289
+ />
290
+ </button>
291
+ <button
292
+ className="group cursor-pointer bg-transparent disabled:cursor-default hover:disabled:bg-transparent hover:bg-accent p-2"
293
+ disabled={actualFrame === selectedFrames.length - 1}
294
+ onClick={() => {
295
+ setActualFrame(selectedFrames.length - 1);
296
+ }}
297
+ >
298
+ <SkipForward
299
+ className="group-disabled:text-accent"
300
+ size={24}
301
+ />
302
+ </button>
303
+ </div>
304
+ </div>
305
+ </div>
306
+ <div className="w-full h-full bg-black">
307
+ <FramePresentationImage
308
+ key={selectedFrames[actualFrame]}
309
+ node={actualNodePresentation as Konva.Group}
310
+ />
311
+ </div>
312
+ </div>
313
+ )}
314
+ </>
315
+ );
316
+ };
@@ -0,0 +1,27 @@
1
+ import Konva from "konva";
2
+
3
+ export const toImageAsync = (
4
+ node: Konva.Node,
5
+ properties: {
6
+ pixelRatio?: number;
7
+ x: number;
8
+ y: number;
9
+ width: number;
10
+ height: number;
11
+ }
12
+ ): Promise<HTMLImageElement> => {
13
+ return new Promise((resolve) => {
14
+ node.toImage({
15
+ mimeType: "image/jpeg",
16
+ quality: 1,
17
+ pixelRatio: properties.pixelRatio ?? 1,
18
+ x: properties.x,
19
+ y: properties.y,
20
+ width: properties.width,
21
+ height: properties.height,
22
+ callback(img) {
23
+ resolve(img);
24
+ },
25
+ });
26
+ });
27
+ };