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,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
+ };
@@ -0,0 +1,69 @@
1
+ import {
2
+ BringToFront,
3
+ ArrowUp,
4
+ ArrowDown,
5
+ SendToBack,
6
+ Group,
7
+ Ungroup,
8
+ } from "lucide-react";
9
+ import { SYSTEM_OS } from "@/lib/utils";
10
+ import { HelpShortcutElement } from "./help-shortcut-element";
11
+
12
+ export const HelpArrange = () => {
13
+ return (
14
+ <div className="w-full grid grid-cols-2 py-3 gap-x-5">
15
+ <div className="flex flex-col gap-3">
16
+ <HelpShortcutElement
17
+ icon={<BringToFront />}
18
+ label="Bring to front"
19
+ shortcuts={{
20
+ [SYSTEM_OS.MAC]: "]",
21
+ [SYSTEM_OS.OTHER]: "]",
22
+ }}
23
+ />
24
+ <HelpShortcutElement
25
+ icon={<ArrowUp />}
26
+ label="Move up"
27
+ shortcuts={{
28
+ [SYSTEM_OS.MAC]: "⌘ ]",
29
+ [SYSTEM_OS.OTHER]: "Ctrl ]",
30
+ }}
31
+ />
32
+ <HelpShortcutElement
33
+ icon={<ArrowDown />}
34
+ label="Move down"
35
+ shortcuts={{
36
+ [SYSTEM_OS.MAC]: "⌘ [",
37
+ [SYSTEM_OS.OTHER]: "Ctrl [",
38
+ }}
39
+ />
40
+ <HelpShortcutElement
41
+ icon={<SendToBack />}
42
+ label="Send to back"
43
+ shortcuts={{
44
+ [SYSTEM_OS.MAC]: "[",
45
+ [SYSTEM_OS.OTHER]: "[",
46
+ }}
47
+ />
48
+ </div>
49
+ <div className="flex flex-col gap-3">
50
+ <HelpShortcutElement
51
+ icon={<Group />}
52
+ label="Group selected elements"
53
+ shortcuts={{
54
+ [SYSTEM_OS.MAC]: "⇧ ⌘ G",
55
+ [SYSTEM_OS.OTHER]: "⇧ Ctrl G",
56
+ }}
57
+ />
58
+ <HelpShortcutElement
59
+ icon={<Ungroup />}
60
+ label="Un-group selected elements"
61
+ shortcuts={{
62
+ [SYSTEM_OS.MAC]: "⇧ ⌘ U",
63
+ [SYSTEM_OS.OTHER]: "⇧ Ctrl U",
64
+ }}
65
+ />
66
+ </div>
67
+ </div>
68
+ );
69
+ };
@@ -0,0 +1,140 @@
1
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
2
+ import {
3
+ Tooltip,
4
+ TooltipContent,
5
+ TooltipProvider,
6
+ TooltipTrigger,
7
+ } from "@/components/ui/tooltip";
8
+ import {
9
+ Drawer,
10
+ DrawerClose,
11
+ DrawerContent,
12
+ DrawerHeader,
13
+ DrawerTitle,
14
+ DrawerTrigger,
15
+ } from "@/components/ui/drawer";
16
+ import { Keyboard, XIcon } from "lucide-react";
17
+ import { SYSTEM_OS } from "@/lib/utils";
18
+ import { HelpTools } from "./help-tools";
19
+ import { ShortcutElement } from "./shortcut-element";
20
+ import React from "react";
21
+ import { useKeyDown } from "../hooks/use-key-down";
22
+ import { useGetOs } from "../hooks/use-get-os";
23
+ import { HelpZoom } from "./help-zoom";
24
+ import { HelpView } from "./help-view";
25
+ import { HelpSelection } from "./help-selection";
26
+ import { HelpEdit } from "./help-edit";
27
+ import { HelpArrange } from "./help-arrange";
28
+
29
+ export const HelpDrawer = () => {
30
+ const os = useGetOs();
31
+
32
+ const [open, setOpen] = React.useState<boolean>(false);
33
+
34
+ useKeyDown(
35
+ () => {
36
+ setOpen((prev) => !prev);
37
+ },
38
+ ["KeyK"],
39
+ (e) => ([SYSTEM_OS.MAC as string].includes(os) ? e.metaKey : e.ctrlKey)
40
+ );
41
+
42
+ return (
43
+ <Drawer modal={false} open={open} onOpenChange={setOpen}>
44
+ <DrawerTrigger>
45
+ <TooltipProvider delayDuration={300}>
46
+ <Tooltip>
47
+ <TooltipTrigger
48
+ asChild
49
+ className="pointer-events-auto cursor-pointer hover:text-black hover:bg-accent w-8 h-8 px-2 py-2"
50
+ >
51
+ <Keyboard />
52
+ </TooltipTrigger>
53
+ <TooltipContent side="top" align="start" className="rounded-none">
54
+ <div className="flex flex-col gap-2 justify-start items-end">
55
+ <p>Keyboard shortcuts</p>
56
+ <ShortcutElement
57
+ variant="light"
58
+ shortcuts={{
59
+ [SYSTEM_OS.MAC]: "⌘ K",
60
+ [SYSTEM_OS.OTHER]: "Ctrl K",
61
+ }}
62
+ />
63
+ </div>
64
+ </TooltipContent>
65
+ </Tooltip>
66
+ </TooltipProvider>
67
+ </DrawerTrigger>
68
+ <DrawerContent className="p-0 !rounded-none bg-black flex flex-col justify-start items-center min-h-[330px]">
69
+ <DrawerHeader className="w-[1024px] flex flex-row justify-between items-centers p-0 py-3">
70
+ <DrawerTitle className="flex flex-row justify-start items-center text-center text-white font-noto-sans-mono">
71
+ Keyboard shortcuts
72
+ </DrawerTitle>
73
+ <DrawerClose>
74
+ <div className="outline-none rounded-none font-noto-sans-mono cursor-pointer text-white">
75
+ <XIcon size={24} />
76
+ </div>
77
+ </DrawerClose>
78
+ </DrawerHeader>
79
+ <Tabs defaultValue="tools" className="w-[1024px] my-5 p-0">
80
+ <TabsList className="w-full bg-zinc-700 rounded-none h-auto">
81
+ <TabsTrigger
82
+ value="tools"
83
+ className="cursor-pointer bg-black rounded-none p-1"
84
+ >
85
+ Tools
86
+ </TabsTrigger>
87
+ <TabsTrigger
88
+ value="view"
89
+ className="cursor-pointer bg-black rounded-none p-1"
90
+ >
91
+ View
92
+ </TabsTrigger>
93
+ <TabsTrigger
94
+ value="zoom"
95
+ className="cursor-pointer bg-black rounded-none p-1"
96
+ >
97
+ Zoom
98
+ </TabsTrigger>
99
+ <TabsTrigger
100
+ value="selection"
101
+ className="cursor-pointer bg-black rounded-none p-1"
102
+ >
103
+ Selection
104
+ </TabsTrigger>
105
+ <TabsTrigger
106
+ value="edit"
107
+ className="cursor-pointer bg-black rounded-none p-1"
108
+ >
109
+ Edit
110
+ </TabsTrigger>
111
+ <TabsTrigger
112
+ value="arrange"
113
+ className="cursor-pointer bg-black rounded-none p-1"
114
+ >
115
+ Arrange
116
+ </TabsTrigger>
117
+ </TabsList>
118
+ <TabsContent value="tools">
119
+ <HelpTools />
120
+ </TabsContent>
121
+ <TabsContent value="view">
122
+ <HelpView />
123
+ </TabsContent>
124
+ <TabsContent value="zoom">
125
+ <HelpZoom />
126
+ </TabsContent>
127
+ <TabsContent value="selection">
128
+ <HelpSelection />
129
+ </TabsContent>
130
+ <TabsContent value="edit">
131
+ <HelpEdit />
132
+ </TabsContent>
133
+ <TabsContent value="arrange">
134
+ <HelpArrange />
135
+ </TabsContent>
136
+ </Tabs>
137
+ </DrawerContent>
138
+ </Drawer>
139
+ );
140
+ };
@@ -0,0 +1,80 @@
1
+ import {
2
+ ClipboardPaste,
3
+ Copy,
4
+ ClipboardCopy,
5
+ ImageDown,
6
+ MonitorDown,
7
+ Undo,
8
+ Redo,
9
+ } from "lucide-react";
10
+ import { SYSTEM_OS } from "@/lib/utils";
11
+ import { HelpShortcutElement } from "./help-shortcut-element";
12
+
13
+ export const HelpEdit = () => {
14
+ return (
15
+ <div className="w-full grid grid-cols-3 py-3 gap-x-5">
16
+ <div className="flex flex-col gap-3">
17
+ <HelpShortcutElement
18
+ icon={<ClipboardCopy />}
19
+ label="Copy"
20
+ shortcuts={{
21
+ [SYSTEM_OS.MAC]: "⌘ C",
22
+ [SYSTEM_OS.OTHER]: "Ctrl C",
23
+ }}
24
+ />
25
+ <HelpShortcutElement
26
+ icon={<ClipboardPaste />}
27
+ label="Paste"
28
+ shortcuts={{
29
+ [SYSTEM_OS.MAC]: "⌘ P",
30
+ [SYSTEM_OS.OTHER]: "Ctrl P",
31
+ }}
32
+ />
33
+ </div>
34
+ <div className="flex flex-col gap-3">
35
+ <HelpShortcutElement
36
+ icon={<Copy />}
37
+ label="Duplicate"
38
+ shortcuts={{
39
+ [SYSTEM_OS.MAC]: "⌘ D",
40
+ [SYSTEM_OS.OTHER]: "Ctrl D",
41
+ }}
42
+ />
43
+ <HelpShortcutElement
44
+ icon={<Undo />}
45
+ label="Undo"
46
+ shortcuts={{
47
+ [SYSTEM_OS.MAC]: "⇧ ⌘ ,",
48
+ [SYSTEM_OS.OTHER]: "⇧ Ctrl ,",
49
+ }}
50
+ />
51
+ <HelpShortcutElement
52
+ icon={<Redo />}
53
+ label="Redo"
54
+ shortcuts={{
55
+ [SYSTEM_OS.MAC]: "⇧ ⌘ .",
56
+ [SYSTEM_OS.OTHER]: "⇧ Ctrl .",
57
+ }}
58
+ />
59
+ </div>
60
+ <div className="flex flex-col gap-3">
61
+ <HelpShortcutElement
62
+ icon={<ImageDown />}
63
+ label="Export selected as image"
64
+ shortcuts={{
65
+ [SYSTEM_OS.MAC]: "⇧ ⌘ E",
66
+ [SYSTEM_OS.OTHER]: "⇧ Ctrl E",
67
+ }}
68
+ />
69
+ <HelpShortcutElement
70
+ icon={<MonitorDown />}
71
+ label="Export viewport as image"
72
+ shortcuts={{
73
+ [SYSTEM_OS.MAC]: "⇧ ⌘ V",
74
+ [SYSTEM_OS.OTHER]: "⇧ Ctrl V",
75
+ }}
76
+ />
77
+ </div>
78
+ </div>
79
+ );
80
+ };
@@ -0,0 +1,30 @@
1
+ import { SquareDashed, TextSelect } from "lucide-react";
2
+ import { SYSTEM_OS } from "@/lib/utils";
3
+ import { HelpShortcutElement } from "./help-shortcut-element";
4
+
5
+ export const HelpSelection = () => {
6
+ return (
7
+ <div className="w-full grid grid-cols-2 py-3 gap-x-5">
8
+ <div className="flex flex-col gap-3">
9
+ <HelpShortcutElement
10
+ icon={<TextSelect />}
11
+ label="Select all"
12
+ shortcuts={{
13
+ [SYSTEM_OS.MAC]: "⇧ ⌘ A",
14
+ [SYSTEM_OS.OTHER]: "⇧ Ctrl A",
15
+ }}
16
+ />
17
+ </div>
18
+ <div className="flex flex-col gap-3">
19
+ <HelpShortcutElement
20
+ icon={<SquareDashed />}
21
+ label="Select none"
22
+ shortcuts={{
23
+ [SYSTEM_OS.MAC]: "⇧ Esc",
24
+ [SYSTEM_OS.OTHER]: "⇧ Esc",
25
+ }}
26
+ />
27
+ </div>
28
+ </div>
29
+ );
30
+ };
@@ -0,0 +1,24 @@
1
+ import React from "react";
2
+ import { ShortcutElement } from "./shortcut-element";
3
+
4
+ type HelpShortcutElement = {
5
+ icon: React.ReactElement;
6
+ label: string;
7
+ shortcuts: Record<string, string>;
8
+ };
9
+
10
+ export const HelpShortcutElement = ({
11
+ icon,
12
+ label,
13
+ shortcuts,
14
+ }: Readonly<HelpShortcutElement>) => {
15
+ return (
16
+ <div className="flex justify-between items-center text-white">
17
+ <div className="flex gap-2 justify-start items-center">
18
+ {React.cloneElement(icon, { size: 20 })}
19
+ <div className="text-white font-noto-sans-mono text-sm">{label}</div>
20
+ </div>
21
+ <ShortcutElement shortcuts={shortcuts} />
22
+ </div>
23
+ );
24
+ };