drawboard-microservice 1.0.7 → 1.0.9
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.
- package/dist/index.css +1 -0
- package/dist/index.js +41234 -0
- package/package.json +14 -4
- package/dist-app/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist-app/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist-app/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist-app/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist-app/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist-app/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist-app/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist-app/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist-app/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist-app/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist-app/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist-app/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist-app/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist-app/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist-app/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist-app/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist-app/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist-app/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist-app/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist-app/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist-app/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist-app/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist-app/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist-app/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist-app/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist-app/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist-app/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist-app/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist-app/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist-app/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist-app/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist-app/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist-app/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist-app/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist-app/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist-app/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist-app/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist-app/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist-app/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist-app/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist-app/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist-app/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist-app/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist-app/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist-app/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist-app/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist-app/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist-app/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist-app/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist-app/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist-app/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist-app/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist-app/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist-app/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist-app/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist-app/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist-app/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist-app/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist-app/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist-app/assets/main-Dm0gV1xN.js +0 -307
- package/dist-app/assets/main-Dm0gV1xN.js.map +0 -1
- package/dist-app/assets/main-uvzSCXM2.css +0 -1
- package/dist-app/index.html +0 -13
- package/dockerfile +0 -14
- package/eslint.config.js +0 -23
- package/index.html +0 -12
- package/public/icon-align-64-default.png +0 -0
- package/public/icon-align-justify-64-active.png +0 -0
- package/public/icon-align-justify-64-default 1.png +0 -0
- package/public/icon-align-justify-64-default.png +0 -0
- package/public/icon-align-justify-64-hover.png +0 -0
- package/public/icon-align-left-64-active.png +0 -0
- package/public/icon-align-left-64-default 1.png +0 -0
- package/public/icon-align-left-64-default.png +0 -0
- package/public/icon-align-left-64-hover.png +0 -0
- package/public/icon-align-right-64-active.png +0 -0
- package/public/icon-align-right-64-default.png +0 -0
- package/public/icon-align-right-64-hover.png +0 -0
- package/public/icon-bold-64-active.png +0 -0
- package/public/icon-bold-64-default 1.png +0 -0
- package/public/icon-bold-64-default.png +0 -0
- package/public/icon-bold-64-hover.png +0 -0
- package/public/icon-broom-64-active.png +0 -0
- package/public/icon-broom-64-default.png +0 -0
- package/public/icon-broom-64-hover.png +0 -0
- package/public/icon-cancel-64-active.png +0 -0
- package/public/icon-cancel-64-default.png +0 -0
- package/public/icon-cancel-64-hover.png +0 -0
- package/public/icon-change-64-active.png +0 -0
- package/public/icon-change-64-default.png +0 -0
- package/public/icon-change-64-hover.png +0 -0
- package/public/icon-circle-64-active.png +0 -0
- package/public/icon-circle-64-default.png +0 -0
- package/public/icon-circle-64-hover.png +0 -0
- package/public/icon-close-64-active.png +0 -0
- package/public/icon-close-64-default.png +0 -0
- package/public/icon-close-64-hover.png +0 -0
- package/public/icon-cursor-64-active.png +0 -0
- package/public/icon-cursor-64-default.png +0 -0
- package/public/icon-cursor-64-hover.png +0 -0
- package/public/icon-delete-trash-64-active.png +0 -0
- package/public/icon-delete-trash-64-default.png +0 -0
- package/public/icon-delete-trash-64-hover.png +0 -0
- package/public/icon-done-64-active.png +0 -0
- package/public/icon-done-64-default.png +0 -0
- package/public/icon-done-64-hover.png +0 -0
- package/public/icon-edit-text-file-64-active.png +0 -0
- package/public/icon-edit-text-file-64-default 1.png +0 -0
- package/public/icon-edit-text-file-64-default.png +0 -0
- package/public/icon-edit-text-file-64-hover.png +0 -0
- package/public/icon-eraser-64-active.png +0 -0
- package/public/icon-eraser-64-default.png +0 -0
- package/public/icon-eraser-64-hover.png +0 -0
- package/public/icon-font-style-64-active.png +0 -0
- package/public/icon-font-style-64-default.png +0 -0
- package/public/icon-font-style-64-hover.png +0 -0
- package/public/icon-formula-fx-64-active.png +0 -0
- package/public/icon-formula-fx-64-default.png +0 -0
- package/public/icon-formula-fx-64-hover.png +0 -0
- package/public/icon-highlighter-64-active.png +0 -0
- package/public/icon-highlighter-64-default.png +0 -0
- package/public/icon-highlighter-64-hover.png +0 -0
- package/public/icon-installing-64-active.png +0 -0
- package/public/icon-installing-64-default.png +0 -0
- package/public/icon-installing-64-hover.png +0 -0
- package/public/icon-italic-64-active.png +0 -0
- package/public/icon-italic-64-default 1.png +0 -0
- package/public/icon-italic-64-default.png +0 -0
- package/public/icon-italic-64-hover.png +0 -0
- package/public/icon-line-64-active.png +0 -0
- package/public/icon-line-64-default.png +0 -0
- package/public/icon-line-64-hover.png +0 -0
- package/public/icon-pen-64-active.png +0 -0
- package/public/icon-pen-64-default.png +0 -0
- package/public/icon-pen-64-hover.png +0 -0
- package/public/icon-pin-64-active.png +0 -0
- package/public/icon-pin-64-default.png +0 -0
- package/public/icon-pin-64-hover.png +0 -0
- package/public/icon-redo-64-active.png +0 -0
- package/public/icon-redo-64-default.png +0 -0
- package/public/icon-redo-64-hover.png +0 -0
- package/public/icon-return-64-active.png +0 -0
- package/public/icon-return-64-default.png +0 -0
- package/public/icon-return-64-hover.png +0 -0
- package/public/icon-select-active.png +0 -0
- package/public/icon-select-default.png +0 -0
- package/public/icon-select-hover.png +0 -0
- package/public/icon-square-64-active.png +0 -0
- package/public/icon-square-64-default.png +0 -0
- package/public/icon-square-64-hover.png +0 -0
- package/public/icon-strikethrough-64-active.png +0 -0
- package/public/icon-strikethrough-64-default 1.png +0 -0
- package/public/icon-strikethrough-64-default.png +0 -0
- package/public/icon-strikethrough-64-hover.png +0 -0
- package/public/icon-text-64-active.png +0 -0
- package/public/icon-text-64-default.png +0 -0
- package/public/icon-text-64-hover.png +0 -0
- package/public/icon-u-turn-to-right-64-active.png +0 -0
- package/public/icon-u-turn-to-right-64-default.png +0 -0
- package/public/icon-u-turn-to-right-64-hover.png +0 -0
- package/public/icon-under-64-active.png +0 -0
- package/public/icon-under-64-default 1.png +0 -0
- package/public/icon-under-64-default.png +0 -0
- package/public/icon-under-64-hover.png +0 -0
- package/src/App.css +0 -887
- package/src/App.tsx +0 -1468
- package/src/assets/icon-broom-64-active.png +0 -0
- package/src/assets/icon-broom-64-default.png +0 -0
- package/src/assets/icon-broom-64-hover.png +0 -0
- package/src/assets/icon-cancel-64-active.png +0 -0
- package/src/assets/icon-cancel-64-default.png +0 -0
- package/src/assets/icon-cancel-64-hover.png +0 -0
- package/src/assets/icon-change-64-active.png +0 -0
- package/src/assets/icon-change-64-default.png +0 -0
- package/src/assets/icon-change-64-hover.png +0 -0
- package/src/assets/icon-circle-64-active.png +0 -0
- package/src/assets/icon-circle-64-default.png +0 -0
- package/src/assets/icon-circle-64-hover.png +0 -0
- package/src/assets/icon-cursor-64-active.png +0 -0
- package/src/assets/icon-cursor-64-default.png +0 -0
- package/src/assets/icon-cursor-64-hover.png +0 -0
- package/src/assets/icon-delete-trash-64-active.png +0 -0
- package/src/assets/icon-delete-trash-64-default.png +0 -0
- package/src/assets/icon-delete-trash-64-hover.png +0 -0
- package/src/assets/icon-eraser-64-active.png +0 -0
- package/src/assets/icon-eraser-64-default.png +0 -0
- package/src/assets/icon-eraser-64-hover.png +0 -0
- package/src/assets/icon-font-style-64-active.png +0 -0
- package/src/assets/icon-font-style-64-default.png +0 -0
- package/src/assets/icon-font-style-64-hover.png +0 -0
- package/src/assets/icon-formula-fx-64-active.png +0 -0
- package/src/assets/icon-formula-fx-64-default.png +0 -0
- package/src/assets/icon-formula-fx-64-hover.png +0 -0
- package/src/assets/icon-highlighter-64-active.png +0 -0
- package/src/assets/icon-highlighter-64-default.png +0 -0
- package/src/assets/icon-highlighter-64-hover.png +0 -0
- package/src/assets/icon-installing-64-active.png +0 -0
- package/src/assets/icon-installing-64-default.png +0 -0
- package/src/assets/icon-installing-64-hover.png +0 -0
- package/src/assets/icon-line-64-active.png +0 -0
- package/src/assets/icon-line-64-default.png +0 -0
- package/src/assets/icon-line-64-hover.png +0 -0
- package/src/assets/icon-minus-64-active.png +0 -0
- package/src/assets/icon-minus-64-default.png +0 -0
- package/src/assets/icon-minus-64-hover.png +0 -0
- package/src/assets/icon-pen-64-active.png +0 -0
- package/src/assets/icon-pen-64-default.png +0 -0
- package/src/assets/icon-pen-64-hover.png +0 -0
- package/src/assets/icon-pin-64-active.png +0 -0
- package/src/assets/icon-pin-64-default.png +0 -0
- package/src/assets/icon-pin-64-hover.png +0 -0
- package/src/assets/icon-plus-64-active.png +0 -0
- package/src/assets/icon-plus-64-default.png +0 -0
- package/src/assets/icon-plus-64-hover.png +0 -0
- package/src/assets/icon-return-64-active.png +0 -0
- package/src/assets/icon-return-64-default.png +0 -0
- package/src/assets/icon-return-64-hover.png +0 -0
- package/src/assets/icon-select-active.png +0 -0
- package/src/assets/icon-select-default.png +0 -0
- package/src/assets/icon-select-hover.png +0 -0
- package/src/assets/icon-square-64-active.png +0 -0
- package/src/assets/icon-square-64-default.png +0 -0
- package/src/assets/icon-square-64-hover.png +0 -0
- package/src/assets/icon-text-64-active.png +0 -0
- package/src/assets/icon-text-64-default.png +0 -0
- package/src/assets/icon-text-64-hover.png +0 -0
- package/src/assets/icon-u-turn-to-right-64-active.png +0 -0
- package/src/assets/icon-u-turn-to-right-64-default.png +0 -0
- package/src/assets/icon-u-turn-to-right-64-hover.png +0 -0
- package/src/components/BrushToolbar.tsx +0 -72
- package/src/components/LatexEditor.tsx +0 -247
- package/src/components/LatexToolbar.tsx +0 -68
- package/src/components/OCRPreview.tsx +0 -234
- package/src/components/OCRToolbar.tsx +0 -46
- package/src/components/RangeToolbar.tsx +0 -33
- package/src/components/SelDelToolbar.tsx +0 -52
- package/src/components/TextEditor.tsx +0 -38
- package/src/components/TextToolbar.tsx +0 -271
- package/src/components/ToolsToolbar.tsx +0 -114
- package/src/constants/fonts.ts +0 -14
- package/src/constants/latexCategories.ts +0 -11
- package/src/constants/latexSymbols.ts +0 -38
- package/src/hooks/useDrawingHandlers.ts +0 -676
- package/src/hooks/useDrawingState.ts +0 -59
- package/src/hooks/useHistory.ts +0 -52
- package/src/hooks/useKeyboard.ts +0 -96
- package/src/hooks/useLatexSymbols.ts +0 -79
- package/src/hooks/useOutsideClick.ts +0 -25
- package/src/hooks/useTextEditing.ts +0 -131
- package/src/hooks/useTextFormatting.ts +0 -153
- package/src/hooks/useWebSocket.ts +0 -202
- package/src/index.ts +0 -4
- package/src/main.tsx +0 -18
- package/src/services/api.ts +0 -81
- package/src/services/statsService.ts +0 -165
- package/src/services/widgetBridge.ts +0 -73
- package/src/types.ts +0 -80
- package/src/utils/colorUtils.ts +0 -6
- package/src/utils/latexUtils.ts +0 -48
- package/src/utils/shapeUtils.ts +0 -151
- package/tsconfig.app.json +0 -28
- package/tsconfig.json +0 -14
- package/tsconfig.node.json +0 -26
- package/vite.config.ts +0 -85
- /package/{dist-app → dist}/icon-align-64-default.png +0 -0
- /package/{dist-app → dist}/icon-align-justify-64-active.png +0 -0
- /package/{dist-app → dist}/icon-align-justify-64-default 1.png +0 -0
- /package/{dist-app → dist}/icon-align-justify-64-default.png +0 -0
- /package/{dist-app → dist}/icon-align-justify-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-align-left-64-active.png +0 -0
- /package/{dist-app → dist}/icon-align-left-64-default 1.png +0 -0
- /package/{dist-app → dist}/icon-align-left-64-default.png +0 -0
- /package/{dist-app → dist}/icon-align-left-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-align-right-64-active.png +0 -0
- /package/{dist-app → dist}/icon-align-right-64-default.png +0 -0
- /package/{dist-app → dist}/icon-align-right-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-bold-64-active.png +0 -0
- /package/{dist-app → dist}/icon-bold-64-default 1.png +0 -0
- /package/{dist-app → dist}/icon-bold-64-default.png +0 -0
- /package/{dist-app → dist}/icon-bold-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-broom-64-active.png +0 -0
- /package/{dist-app → dist}/icon-broom-64-default.png +0 -0
- /package/{dist-app → dist}/icon-broom-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-cancel-64-active.png +0 -0
- /package/{dist-app → dist}/icon-cancel-64-default.png +0 -0
- /package/{dist-app → dist}/icon-cancel-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-change-64-active.png +0 -0
- /package/{dist-app → dist}/icon-change-64-default.png +0 -0
- /package/{dist-app → dist}/icon-change-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-circle-64-active.png +0 -0
- /package/{dist-app → dist}/icon-circle-64-default.png +0 -0
- /package/{dist-app → dist}/icon-circle-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-close-64-active.png +0 -0
- /package/{dist-app → dist}/icon-close-64-default.png +0 -0
- /package/{dist-app → dist}/icon-close-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-cursor-64-active.png +0 -0
- /package/{dist-app → dist}/icon-cursor-64-default.png +0 -0
- /package/{dist-app → dist}/icon-cursor-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-delete-trash-64-active.png +0 -0
- /package/{dist-app → dist}/icon-delete-trash-64-default.png +0 -0
- /package/{dist-app → dist}/icon-delete-trash-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-done-64-active.png +0 -0
- /package/{dist-app → dist}/icon-done-64-default.png +0 -0
- /package/{dist-app → dist}/icon-done-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-edit-text-file-64-active.png +0 -0
- /package/{dist-app → dist}/icon-edit-text-file-64-default 1.png +0 -0
- /package/{dist-app → dist}/icon-edit-text-file-64-default.png +0 -0
- /package/{dist-app → dist}/icon-edit-text-file-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-eraser-64-active.png +0 -0
- /package/{dist-app → dist}/icon-eraser-64-default.png +0 -0
- /package/{dist-app → dist}/icon-eraser-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-font-style-64-active.png +0 -0
- /package/{dist-app → dist}/icon-font-style-64-default.png +0 -0
- /package/{dist-app → dist}/icon-font-style-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-formula-fx-64-active.png +0 -0
- /package/{dist-app → dist}/icon-formula-fx-64-default.png +0 -0
- /package/{dist-app → dist}/icon-formula-fx-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-highlighter-64-active.png +0 -0
- /package/{dist-app → dist}/icon-highlighter-64-default.png +0 -0
- /package/{dist-app → dist}/icon-highlighter-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-installing-64-active.png +0 -0
- /package/{dist-app → dist}/icon-installing-64-default.png +0 -0
- /package/{dist-app → dist}/icon-installing-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-italic-64-active.png +0 -0
- /package/{dist-app → dist}/icon-italic-64-default 1.png +0 -0
- /package/{dist-app → dist}/icon-italic-64-default.png +0 -0
- /package/{dist-app → dist}/icon-italic-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-line-64-active.png +0 -0
- /package/{dist-app → dist}/icon-line-64-default.png +0 -0
- /package/{dist-app → dist}/icon-line-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-pen-64-active.png +0 -0
- /package/{dist-app → dist}/icon-pen-64-default.png +0 -0
- /package/{dist-app → dist}/icon-pen-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-pin-64-active.png +0 -0
- /package/{dist-app → dist}/icon-pin-64-default.png +0 -0
- /package/{dist-app → dist}/icon-pin-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-redo-64-active.png +0 -0
- /package/{dist-app → dist}/icon-redo-64-default.png +0 -0
- /package/{dist-app → dist}/icon-redo-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-return-64-active.png +0 -0
- /package/{dist-app → dist}/icon-return-64-default.png +0 -0
- /package/{dist-app → dist}/icon-return-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-select-active.png +0 -0
- /package/{dist-app → dist}/icon-select-default.png +0 -0
- /package/{dist-app → dist}/icon-select-hover.png +0 -0
- /package/{dist-app → dist}/icon-square-64-active.png +0 -0
- /package/{dist-app → dist}/icon-square-64-default.png +0 -0
- /package/{dist-app → dist}/icon-square-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-strikethrough-64-active.png +0 -0
- /package/{dist-app → dist}/icon-strikethrough-64-default 1.png +0 -0
- /package/{dist-app → dist}/icon-strikethrough-64-default.png +0 -0
- /package/{dist-app → dist}/icon-strikethrough-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-text-64-active.png +0 -0
- /package/{dist-app → dist}/icon-text-64-default.png +0 -0
- /package/{dist-app → dist}/icon-text-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-u-turn-to-right-64-active.png +0 -0
- /package/{dist-app → dist}/icon-u-turn-to-right-64-default.png +0 -0
- /package/{dist-app → dist}/icon-u-turn-to-right-64-hover.png +0 -0
- /package/{dist-app → dist}/icon-under-64-active.png +0 -0
- /package/{dist-app → dist}/icon-under-64-default 1.png +0 -0
- /package/{dist-app → dist}/icon-under-64-default.png +0 -0
- /package/{dist-app → dist}/icon-under-64-hover.png +0 -0
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef, useCallback, useState, useMemo } from 'react';
|
|
2
|
-
import type { Shape } from '../types';
|
|
3
|
-
|
|
4
|
-
const WS_BASE_URL =
|
|
5
|
-
import.meta.env.VITE_PUBLIC_WS_URL || 'ws://localhost:8000';
|
|
6
|
-
|
|
7
|
-
export interface WebSocketMessage {
|
|
8
|
-
type: 'init' | 'update' | 'clear' | 'undo' | 'shapes';
|
|
9
|
-
data?: any;
|
|
10
|
-
userId?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface CanvasData {
|
|
14
|
-
shapes: Shape[];
|
|
15
|
-
config?: any;
|
|
16
|
-
history?: any[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const useWebSocket = (
|
|
20
|
-
boardId: string,
|
|
21
|
-
onCanvasUpdate: (data: CanvasData) => void,
|
|
22
|
-
userId: string = crypto.randomUUID()
|
|
23
|
-
) => {
|
|
24
|
-
const wsRef = useRef<WebSocket | null>(null);
|
|
25
|
-
const onCanvasUpdateRef = useRef(onCanvasUpdate);
|
|
26
|
-
const reconnectTimerRef = useRef<number | null>(null);
|
|
27
|
-
const reconnectAttempts = useRef(0);
|
|
28
|
-
|
|
29
|
-
// ⬇️ Используем useRef для стабильных значений
|
|
30
|
-
const boardIdRef = useRef(boardId);
|
|
31
|
-
const userIdRef = useRef(userId);
|
|
32
|
-
|
|
33
|
-
const MAX_RECONNECT_ATTEMPTS = 5;
|
|
34
|
-
const RECONNECT_DELAY = 1500;
|
|
35
|
-
|
|
36
|
-
const [isConnected, setIsConnected] = useState(false);
|
|
37
|
-
|
|
38
|
-
// Обновляем refs при изменении пропсов
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
boardIdRef.current = boardId;
|
|
41
|
-
}, [boardId]);
|
|
42
|
-
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
userIdRef.current = userId;
|
|
45
|
-
}, [userId]);
|
|
46
|
-
|
|
47
|
-
// Всегда актуальный callback
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
onCanvasUpdateRef.current = onCanvasUpdate;
|
|
50
|
-
}, [onCanvasUpdate]);
|
|
51
|
-
|
|
52
|
-
// ⬇️ connect больше не зависит от изменяющихся пропсов
|
|
53
|
-
const connect = useCallback(() => {
|
|
54
|
-
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
|
55
|
-
console.log('[WS] Already connected, skipping');
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Закрываем существующее соединение
|
|
60
|
-
if (wsRef.current) {
|
|
61
|
-
wsRef.current.close();
|
|
62
|
-
wsRef.current = null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const ws = new WebSocket(
|
|
66
|
-
`${WS_BASE_URL}/ws/canvas/${boardIdRef.current}/`
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
wsRef.current = ws;
|
|
70
|
-
|
|
71
|
-
ws.onopen = () => {
|
|
72
|
-
console.log('[WS] Connected to board:', boardIdRef.current);
|
|
73
|
-
setIsConnected(true);
|
|
74
|
-
reconnectAttempts.current = 0;
|
|
75
|
-
|
|
76
|
-
// Запрашиваем начальное состояние
|
|
77
|
-
ws.send(JSON.stringify({
|
|
78
|
-
type: 'init',
|
|
79
|
-
userId: userIdRef.current
|
|
80
|
-
}));
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
ws.onmessage = (event) => {
|
|
84
|
-
try {
|
|
85
|
-
const message: WebSocketMessage = JSON.parse(event.data);
|
|
86
|
-
|
|
87
|
-
if (message.userId === userIdRef.current) return;
|
|
88
|
-
|
|
89
|
-
switch (message.type) {
|
|
90
|
-
case 'init':
|
|
91
|
-
if (message.data) {
|
|
92
|
-
onCanvasUpdateRef.current(message.data);
|
|
93
|
-
}
|
|
94
|
-
break;
|
|
95
|
-
|
|
96
|
-
case 'update':
|
|
97
|
-
case 'shapes':
|
|
98
|
-
case 'undo':
|
|
99
|
-
if (message.data) {
|
|
100
|
-
onCanvasUpdateRef.current(message.data);
|
|
101
|
-
}
|
|
102
|
-
break;
|
|
103
|
-
|
|
104
|
-
case 'clear':
|
|
105
|
-
onCanvasUpdateRef.current({ shapes: [], config: {}, history: [] });
|
|
106
|
-
break;
|
|
107
|
-
|
|
108
|
-
default:
|
|
109
|
-
console.warn('[WS] Unknown message type:', message.type);
|
|
110
|
-
}
|
|
111
|
-
} catch (e) {
|
|
112
|
-
console.error('[WS] Message parse error:', e);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
ws.onerror = (e) => {
|
|
117
|
-
console.error('[WS] Connection error:', e);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
ws.onclose = (event) => {
|
|
121
|
-
console.log('[WS] Disconnected, code:', event.code, 'reason:', event.reason);
|
|
122
|
-
setIsConnected(false);
|
|
123
|
-
wsRef.current = null;
|
|
124
|
-
|
|
125
|
-
// Не переподключаемся при нормальном закрытии
|
|
126
|
-
if (event.code === 1000) return;
|
|
127
|
-
|
|
128
|
-
if (reconnectAttempts.current < MAX_RECONNECT_ATTEMPTS) {
|
|
129
|
-
reconnectAttempts.current += 1;
|
|
130
|
-
console.log(`[WS] Reconnecting in ${RECONNECT_DELAY * reconnectAttempts.current}ms (attempt ${reconnectAttempts.current})`);
|
|
131
|
-
|
|
132
|
-
reconnectTimerRef.current = window.setTimeout(() => {
|
|
133
|
-
connect();
|
|
134
|
-
}, RECONNECT_DELAY * reconnectAttempts.current);
|
|
135
|
-
} else {
|
|
136
|
-
console.error('[WS] Max reconnection attempts reached');
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
}, []); // ⬅️ Пустой массив зависимостей - функция создается один раз
|
|
140
|
-
|
|
141
|
-
const disconnect = useCallback(() => {
|
|
142
|
-
// Очищаем таймер переподключения
|
|
143
|
-
if (reconnectTimerRef.current) {
|
|
144
|
-
clearTimeout(reconnectTimerRef.current);
|
|
145
|
-
reconnectTimerRef.current = null;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Закрываем соединение с кодом 1000 (нормальное закрытие)
|
|
149
|
-
if (wsRef.current) {
|
|
150
|
-
wsRef.current.close(1000, 'Client disconnect');
|
|
151
|
-
wsRef.current = null;
|
|
152
|
-
setIsConnected(false);
|
|
153
|
-
}
|
|
154
|
-
}, []);
|
|
155
|
-
|
|
156
|
-
const sendMessage = useCallback((message: WebSocketMessage) => {
|
|
157
|
-
if (wsRef.current?.readyState === WebSocket.OPEN) {
|
|
158
|
-
wsRef.current.send(
|
|
159
|
-
JSON.stringify({ ...message, userId: userIdRef.current })
|
|
160
|
-
);
|
|
161
|
-
} else {
|
|
162
|
-
console.warn('[WS] Cannot send message - connection not open');
|
|
163
|
-
}
|
|
164
|
-
}, []);
|
|
165
|
-
|
|
166
|
-
const sendShapesUpdate = useCallback(
|
|
167
|
-
(shapes: Shape[]) => {
|
|
168
|
-
sendMessage({
|
|
169
|
-
type: 'update',
|
|
170
|
-
data: { shapes },
|
|
171
|
-
});
|
|
172
|
-
},
|
|
173
|
-
[sendMessage]
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
const sendClear = useCallback(() => {
|
|
177
|
-
sendMessage({ type: 'clear' });
|
|
178
|
-
}, [sendMessage]);
|
|
179
|
-
|
|
180
|
-
const sendUndo = useCallback(() => {
|
|
181
|
-
sendMessage({ type: 'undo' });
|
|
182
|
-
}, [sendMessage]);
|
|
183
|
-
|
|
184
|
-
// ⬇️ Ключевое исправление - эффект зависит только от boardId
|
|
185
|
-
useEffect(() => {
|
|
186
|
-
console.log('[WS] Setting up connection for board:', boardId);
|
|
187
|
-
connect();
|
|
188
|
-
|
|
189
|
-
return () => {
|
|
190
|
-
console.log('[WS] Cleaning up connection for board:', boardId);
|
|
191
|
-
disconnect();
|
|
192
|
-
};
|
|
193
|
-
}, [boardId]); // ⬅️ Только boardId вызывает переподключение
|
|
194
|
-
|
|
195
|
-
// Мемоизируем возвращаемый объект, чтобы не вызывать перерендеры
|
|
196
|
-
return useMemo(() => ({
|
|
197
|
-
sendShapesUpdate,
|
|
198
|
-
sendClear,
|
|
199
|
-
sendUndo,
|
|
200
|
-
isConnected,
|
|
201
|
-
}), [sendShapesUpdate, sendClear, sendUndo, isConnected]);
|
|
202
|
-
};
|
package/src/index.ts
DELETED
package/src/main.tsx
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import ReactDOM from 'react-dom/client';
|
|
3
|
-
import { getInfo } from './services/widgetBridge';
|
|
4
|
-
import DrawingApp from './App.tsx';
|
|
5
|
-
|
|
6
|
-
// 👇 Делаем доступным из консоли и iframe
|
|
7
|
-
(window as any).getInfo = getInfo;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const root = ReactDOM.createRoot(
|
|
11
|
-
document.getElementById('root') as HTMLElement
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
root.render(
|
|
15
|
-
<React.StrictMode>
|
|
16
|
-
<DrawingApp />
|
|
17
|
-
</React.StrictMode>
|
|
18
|
-
);
|
package/src/services/api.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
// API service for sending canvas commands to backend
|
|
2
|
-
// Added for backend data sending logic
|
|
3
|
-
|
|
4
|
-
const API_BASE_URL = 'http://localhost:8000'; // Adjust to your backend URL
|
|
5
|
-
|
|
6
|
-
export interface ApiResponse {
|
|
7
|
-
success: boolean;
|
|
8
|
-
message?: string;
|
|
9
|
-
data?: any;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const sendCanvasCommand = async (
|
|
13
|
-
boardId: string,
|
|
14
|
-
action: 'clear' | 'undo' | 'update',
|
|
15
|
-
data?: any
|
|
16
|
-
): Promise<ApiResponse> => {
|
|
17
|
-
try {
|
|
18
|
-
const url = `${API_BASE_URL}/api/canvas/${boardId}/${action}/`;
|
|
19
|
-
|
|
20
|
-
const response = await fetch(url, {
|
|
21
|
-
method: 'POST',
|
|
22
|
-
headers: {
|
|
23
|
-
'Content-Type': 'application/json',
|
|
24
|
-
},
|
|
25
|
-
body: JSON.stringify(data || {}),
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
if (!response.ok) {
|
|
29
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const result = await response.json();
|
|
33
|
-
return result;
|
|
34
|
-
} catch (error) {
|
|
35
|
-
console.error('API Error:', error);
|
|
36
|
-
return { success: false, message: error instanceof Error ? error.message : 'Unknown error' };
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
// OCR функция для отправки изображения
|
|
41
|
-
export const sendOcrImage = async (imageData: string): Promise<ApiResponse> => {
|
|
42
|
-
try {
|
|
43
|
-
const url = `${API_BASE_URL}/api/ocr/latex/`;
|
|
44
|
-
|
|
45
|
-
const response = await fetch(url, {
|
|
46
|
-
method: 'POST',
|
|
47
|
-
headers: {
|
|
48
|
-
'Content-Type': 'application/json',
|
|
49
|
-
},
|
|
50
|
-
body: JSON.stringify({ image_data: imageData }),
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
if (!response.ok) {
|
|
54
|
-
throw new Error(`HTTP error! status: ${response.status}`);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const result = await response.json();
|
|
58
|
-
return result;
|
|
59
|
-
} catch (error) {
|
|
60
|
-
console.error('OCR API Error:', error);
|
|
61
|
-
return { success: false, message: error instanceof Error ? error.message : 'Unknown error' };
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// Specific functions for each action
|
|
66
|
-
export const clearCanvas = async (boardId: string): Promise<ApiResponse> => {
|
|
67
|
-
return sendCanvasCommand(boardId, 'clear');
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
export const undoAction = async (boardId: string): Promise<ApiResponse> => {
|
|
71
|
-
return sendCanvasCommand(boardId, 'undo');
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
export const updateCanvasData = async (boardId: string, data: { shapes: any[], config?: any, history?: any[] }): Promise<ApiResponse> => {
|
|
75
|
-
return sendCanvasCommand(boardId, 'update', data);
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
// Legacy function for backward compatibility
|
|
79
|
-
export const updateShapes = async (boardId: string, shapes: any[]): Promise<ApiResponse> => {
|
|
80
|
-
return updateCanvasData(boardId, { shapes });
|
|
81
|
-
};
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
import type { CanvasData } from '../hooks/useWebSocket';
|
|
3
|
-
|
|
4
|
-
export interface MetricsData {
|
|
5
|
-
shapesCount: number;
|
|
6
|
-
toolsUsage: Record<string, number>;
|
|
7
|
-
lastUpdated: string;
|
|
8
|
-
sessionDuration?: number;
|
|
9
|
-
boardId: string;
|
|
10
|
-
widgetId: number | null;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface WidgetConfig {
|
|
14
|
-
shapes: any[];
|
|
15
|
-
config: any;
|
|
16
|
-
lastModified: string;
|
|
17
|
-
version: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
class StatsService {
|
|
21
|
-
private baseURL = 'https://statservice.example.com';
|
|
22
|
-
private moduleToken: string | null = null;
|
|
23
|
-
private rateLimitCache = new Map<string, { count: number; resetTime: number }>();
|
|
24
|
-
private readonly RATE_LIMIT_WINDOW = 60 * 60 * 1000; // 60 minutes
|
|
25
|
-
private readonly MAX_REQUESTS = 12;
|
|
26
|
-
|
|
27
|
-
constructor() {
|
|
28
|
-
this.loadToken();
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
private loadToken() {
|
|
32
|
-
const savedToken = localStorage.getItem('moduleToken');
|
|
33
|
-
if (savedToken) {
|
|
34
|
-
this.moduleToken = savedToken;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
private saveToken(token: string) {
|
|
39
|
-
this.moduleToken = token;
|
|
40
|
-
localStorage.setItem('moduleToken', token);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async createModule(moduleName: string): Promise<{
|
|
44
|
-
moduleId: number;
|
|
45
|
-
moduleName: string;
|
|
46
|
-
token: string;
|
|
47
|
-
tokenExpired: string;
|
|
48
|
-
}> {
|
|
49
|
-
try {
|
|
50
|
-
const response = await fetch(`${this.baseURL}/api/stats/module/create`, {
|
|
51
|
-
method: 'POST',
|
|
52
|
-
headers: {
|
|
53
|
-
'Content-Type': 'application/json',
|
|
54
|
-
},
|
|
55
|
-
body: JSON.stringify({ moduleName })
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
if (!response.ok) {
|
|
59
|
-
throw new Error(`Failed to create module: ${response.statusText}`);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const data = await response.json();
|
|
63
|
-
this.saveToken(data.token);
|
|
64
|
-
return data;
|
|
65
|
-
} catch (error) {
|
|
66
|
-
console.error('Error creating module:', error);
|
|
67
|
-
throw error;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private checkRateLimit(): boolean {
|
|
72
|
-
const now = Date.now();
|
|
73
|
-
const moduleKey = this.moduleToken || 'anonymous';
|
|
74
|
-
|
|
75
|
-
const limitInfo = this.rateLimitCache.get(moduleKey);
|
|
76
|
-
|
|
77
|
-
if (!limitInfo) {
|
|
78
|
-
this.rateLimitCache.set(moduleKey, {
|
|
79
|
-
count: 1,
|
|
80
|
-
resetTime: now + this.RATE_LIMIT_WINDOW
|
|
81
|
-
});
|
|
82
|
-
return true;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (now > limitInfo.resetTime) {
|
|
86
|
-
this.rateLimitCache.set(moduleKey, {
|
|
87
|
-
count: 1,
|
|
88
|
-
resetTime: now + this.RATE_LIMIT_WINDOW
|
|
89
|
-
});
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (limitInfo.count >= this.MAX_REQUESTS) {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
limitInfo.count++;
|
|
98
|
-
return true;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async sendMetrics(metrics: MetricsData): Promise<{ moduleId: number; metricId: number }> {
|
|
102
|
-
if (!this.moduleToken) {
|
|
103
|
-
throw new Error('Module token not set. Please create module first.');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (!this.checkRateLimit()) {
|
|
107
|
-
throw new Error('Rate limit exceeded. Please try again later.');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
const response = await fetch(`${this.baseURL}/api/stats/module/metrics`, {
|
|
112
|
-
method: 'PUT',
|
|
113
|
-
headers: {
|
|
114
|
-
'X-Module-Token': this.moduleToken,
|
|
115
|
-
'Content-Type': 'application/json',
|
|
116
|
-
},
|
|
117
|
-
body: JSON.stringify(metrics)
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
if (response.status === 429) {
|
|
121
|
-
const retryAfter = response.headers.get('Retry-After');
|
|
122
|
-
throw new Error(`Rate limit exceeded. Retry after ${retryAfter} seconds`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
if (!response.ok) {
|
|
126
|
-
throw new Error(`Failed to send metrics: ${response.statusText}`);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return await response.json();
|
|
130
|
-
} catch (error) {
|
|
131
|
-
console.error('Error sending metrics:', error);
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async getMetrics(): Promise<any> {
|
|
137
|
-
if (!this.moduleToken) {
|
|
138
|
-
throw new Error('Module token not set');
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
const response = await fetch(`${this.baseURL}/api/stats/module/metrics`, {
|
|
143
|
-
method: 'GET',
|
|
144
|
-
headers: {
|
|
145
|
-
'X-Module-Token': this.moduleToken,
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
if (response.status === 404) {
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (!response.ok) {
|
|
154
|
-
throw new Error(`Failed to get metrics: ${response.statusText}`);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return await response.json();
|
|
158
|
-
} catch (error) {
|
|
159
|
-
console.error('Error getting metrics:', error);
|
|
160
|
-
throw error;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export const statsService = new StatsService();
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
// widgetBridge.ts
|
|
2
|
-
export interface WidgetInitPayload {
|
|
3
|
-
widgetId: number;
|
|
4
|
-
userId: number;
|
|
5
|
-
role: string;
|
|
6
|
-
config: any;
|
|
7
|
-
board: {
|
|
8
|
-
id: number;
|
|
9
|
-
name: string;
|
|
10
|
-
parentId: number;
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let widgetContext: WidgetInitPayload | null = null;
|
|
15
|
-
let onInitializedCallbacks: Array<(payload: WidgetInitPayload) => void> = [];
|
|
16
|
-
|
|
17
|
-
export const getInfo = (payload: WidgetInitPayload) => {
|
|
18
|
-
if (!payload?.board?.id || typeof payload.board.id !== 'number') {
|
|
19
|
-
throw new Error('Invalid board.id');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (typeof payload.widgetId !== 'number') {
|
|
23
|
-
throw new Error('Invalid widgetId');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
widgetContext = payload;
|
|
27
|
-
|
|
28
|
-
console.log('[Widget] Initialized with:', payload);
|
|
29
|
-
|
|
30
|
-
// Уведомляем всех подписчиков
|
|
31
|
-
onInitializedCallbacks.forEach(callback => callback(payload));
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
widgetId: payload.widgetId,
|
|
35
|
-
boardId: String(payload.board.id),
|
|
36
|
-
userId: payload.userId,
|
|
37
|
-
role: payload.role,
|
|
38
|
-
config: payload.config,
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const getWidgetContext = () => {
|
|
43
|
-
if (!widgetContext) {
|
|
44
|
-
throw new Error('Widget not initialized. Call getInfo first.');
|
|
45
|
-
}
|
|
46
|
-
return widgetContext;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// Подписка на инициализацию виджета
|
|
50
|
-
export const onWidgetInitialized = (callback: (payload: WidgetInitPayload) => void) => {
|
|
51
|
-
onInitializedCallbacks.push(callback);
|
|
52
|
-
|
|
53
|
-
// Если виджет уже инициализирован, вызываем callback сразу
|
|
54
|
-
if (widgetContext) {
|
|
55
|
-
callback(widgetContext);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Функция для отписки
|
|
59
|
-
return () => {
|
|
60
|
-
const index = onInitializedCallbacks.indexOf(callback);
|
|
61
|
-
if (index > -1) {
|
|
62
|
-
onInitializedCallbacks.splice(index, 1);
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// Получение только boardId (для обратной совместимости)
|
|
68
|
-
export const getBoardId = (): string => {
|
|
69
|
-
if (!widgetContext) {
|
|
70
|
-
throw new Error('Widget not initialized');
|
|
71
|
-
}
|
|
72
|
-
return String(widgetContext.board.id);
|
|
73
|
-
};
|
package/src/types.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
export type ShapeType = 'rectangle' | 'ellipse' | 'line' | 'path' | 'text' | 'latex' | 'highlighter';
|
|
2
|
-
export type ToolMode =
|
|
3
|
-
| 'select'
|
|
4
|
-
| 'rectangle'
|
|
5
|
-
| 'ellipse'
|
|
6
|
-
| 'line'
|
|
7
|
-
| 'pencil'
|
|
8
|
-
| 'eraser'
|
|
9
|
-
| 'text'
|
|
10
|
-
| 'latex'
|
|
11
|
-
| 'highlighter'
|
|
12
|
-
| 'ocr-selection';
|
|
13
|
-
export type AnchorType = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | null;
|
|
14
|
-
export type TextAlign = 'left' | 'center' | 'right';
|
|
15
|
-
|
|
16
|
-
export interface Shape {
|
|
17
|
-
id: string;
|
|
18
|
-
type: ShapeType;
|
|
19
|
-
x: number;
|
|
20
|
-
y: number;
|
|
21
|
-
width: number;
|
|
22
|
-
height: number;
|
|
23
|
-
stroke: string;
|
|
24
|
-
strokeWidth: number;
|
|
25
|
-
fill?: string;
|
|
26
|
-
dash?: number[];
|
|
27
|
-
points?: number[];
|
|
28
|
-
opacity?: number;
|
|
29
|
-
isSelected?: boolean;
|
|
30
|
-
text?: string;
|
|
31
|
-
latex?: string;
|
|
32
|
-
fontSize?: number;
|
|
33
|
-
fontFamily?: string;
|
|
34
|
-
textAlign?: TextAlign;
|
|
35
|
-
isEditing?: boolean;
|
|
36
|
-
fontWeight?: 'normal' | 'bold';
|
|
37
|
-
fontStyle?: 'normal' | 'italic';
|
|
38
|
-
textDecoration?: 'none' | 'underline' | 'line-through' | 'underline line-through';
|
|
39
|
-
isLatex?: boolean;
|
|
40
|
-
latexRendered?: string;
|
|
41
|
-
scaleX?: number;
|
|
42
|
-
scaleY?: number;
|
|
43
|
-
rotation?: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface DrawingState {
|
|
47
|
-
isDrawing: boolean;
|
|
48
|
-
startX: number;
|
|
49
|
-
startY: number;
|
|
50
|
-
currentShape: Partial<Shape> | null;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface TransformState {
|
|
54
|
-
isTransforming: boolean;
|
|
55
|
-
shapeId: string | null;
|
|
56
|
-
startWidth: number;
|
|
57
|
-
startHeight: number;
|
|
58
|
-
startX: number;
|
|
59
|
-
startY: number;
|
|
60
|
-
startMouseX: number;
|
|
61
|
-
startMouseY: number;
|
|
62
|
-
anchor: AnchorType;
|
|
63
|
-
originalPoints?: number[];
|
|
64
|
-
originalBbox?: { x: number, y: number, width: number, height: number };
|
|
65
|
-
startFontSize?: number;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface LatexSymbol {
|
|
69
|
-
name: string;
|
|
70
|
-
latex: string;
|
|
71
|
-
description: string;
|
|
72
|
-
category: 'fraction' | 'root' | 'superscript' | 'subscript' | 'brackets' | 'operators' | 'symbols';
|
|
73
|
-
placeholder?: string;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface LatexCategory {
|
|
77
|
-
id: string;
|
|
78
|
-
name: string;
|
|
79
|
-
icon: string;
|
|
80
|
-
}
|
package/src/utils/colorUtils.ts
DELETED
package/src/utils/latexUtils.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
import katex from 'katex';
|
|
3
|
-
|
|
4
|
-
export const renderLatexToHtml = (latex: string, fontSize: number = 20): string => {
|
|
5
|
-
try {
|
|
6
|
-
return katex.renderToString(latex, {
|
|
7
|
-
throwOnError: false,
|
|
8
|
-
displayMode: false,
|
|
9
|
-
output: 'html',
|
|
10
|
-
strict: false,
|
|
11
|
-
fontSize: `${fontSize}px`
|
|
12
|
-
});
|
|
13
|
-
} catch (error) {
|
|
14
|
-
console.error('LaTeX rendering error:', error);
|
|
15
|
-
return `<span style="color: red;">LaTeX error: ${latex}</span>`;
|
|
16
|
-
}
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const measureLatexSize = (latex: string, fontSize: number): { width: number, height: number } => {
|
|
20
|
-
const container = document.createElement('div');
|
|
21
|
-
container.style.position = 'absolute';
|
|
22
|
-
container.style.visibility = 'hidden';
|
|
23
|
-
container.style.display = 'inline-block';
|
|
24
|
-
container.style.fontSize = `${fontSize}px`;
|
|
25
|
-
container.style.padding = '0';
|
|
26
|
-
container.style.margin = '0';
|
|
27
|
-
container.style.lineHeight = '1';
|
|
28
|
-
document.body.appendChild(container);
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
katex.render(latex, container, {
|
|
32
|
-
throwOnError: false,
|
|
33
|
-
displayMode: false,
|
|
34
|
-
output: 'html',
|
|
35
|
-
strict: false
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const width = container.offsetWidth + 20;
|
|
39
|
-
const height = container.offsetHeight + 10;
|
|
40
|
-
|
|
41
|
-
return { width, height };
|
|
42
|
-
} catch (error) {
|
|
43
|
-
console.error('LaTeX measurement error:', error);
|
|
44
|
-
return { width: 200, height: 50 };
|
|
45
|
-
} finally {
|
|
46
|
-
document.body.removeChild(container);
|
|
47
|
-
}
|
|
48
|
-
};
|