From a91f80c1ba986e25531b11f5c637e81b4e3c7e9d Mon Sep 17 00:00:00 2001 From: abearxiong Date: Sun, 23 Feb 2025 02:25:11 +0800 Subject: [PATCH] add wallnote --- package.json | 27 +- pnpm-lock.yaml | 1515 ++++++++++++++++++-- src/App.tsx | 28 +- src/index.css | 34 +- src/modules/dayjs.ts | 11 + src/modules/layouts/Auth.tsx | 24 + src/modules/md2html.ts | 10 + src/modules/message.ts | 23 + src/modules/query.ts | 17 + src/modules/require-to-login.ts | 36 + src/modules/tiptap/editor.ts | 98 ++ src/pages/editor/index.tsx | 32 + src/pages/wall/components/Icon.tsx | 21 + src/pages/wall/constants.ts | 1 + src/pages/wall/hooks/check-double-click.ts | 35 + src/pages/wall/hooks/tab-node.ts | 62 + src/pages/wall/index.tsx | 174 +++ src/pages/wall/modules/CustomNode.css | 149 ++ src/pages/wall/modules/CustomNode.tsx | 150 ++ src/pages/wall/modules/Drawer.tsx | 106 ++ src/pages/wall/modules/FormDialog.tsx | 132 ++ src/pages/wall/modules/toolbar/Toolbar.tsx | 272 ++++ src/pages/wall/pages/List.tsx | 64 + src/pages/wall/store/user-wall.ts | 104 ++ src/pages/wall/store/wall.ts | 162 +++ src/pages/wall/utils/convet.ts | 0 src/pages/wall/utils/db.ts | 14 + src/pages/wall/utils/is-mac.ts | 11 + src/pages/wall/utils/random.ts | 10 + vite.config.ts | 28 +- 30 files changed, 3207 insertions(+), 143 deletions(-) create mode 100644 src/modules/dayjs.ts create mode 100644 src/modules/layouts/Auth.tsx create mode 100644 src/modules/md2html.ts create mode 100644 src/modules/message.ts create mode 100644 src/modules/query.ts create mode 100644 src/modules/require-to-login.ts create mode 100644 src/modules/tiptap/editor.ts create mode 100644 src/pages/editor/index.tsx create mode 100644 src/pages/wall/components/Icon.tsx create mode 100644 src/pages/wall/constants.ts create mode 100644 src/pages/wall/hooks/check-double-click.ts create mode 100644 src/pages/wall/hooks/tab-node.ts create mode 100644 src/pages/wall/index.tsx create mode 100644 src/pages/wall/modules/CustomNode.css create mode 100644 src/pages/wall/modules/CustomNode.tsx create mode 100644 src/pages/wall/modules/Drawer.tsx create mode 100644 src/pages/wall/modules/FormDialog.tsx create mode 100644 src/pages/wall/modules/toolbar/Toolbar.tsx create mode 100644 src/pages/wall/pages/List.tsx create mode 100644 src/pages/wall/store/user-wall.ts create mode 100644 src/pages/wall/store/wall.ts create mode 100644 src/pages/wall/utils/convet.ts create mode 100644 src/pages/wall/utils/db.ts create mode 100644 src/pages/wall/utils/is-mac.ts create mode 100644 src/pages/wall/utils/random.ts diff --git a/package.json b/package.json index ad9b5c9..848b971 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { - "name": "vite-react", + "name": "wallnote", "private": true, - "version": "0.0.1", + "version": "0.0.2", "type": "module", + "user": "apps", "scripts": { "dev": "vite", "dev:web": "cross-env WEB_DEV=true vite --mode web", @@ -10,7 +11,8 @@ "lint": "eslint .", "deploy": "rsync -avz --delete dist/ light:~/apps/ai/dist", "preview": "vite preview", - "pub": "envision deploy ./dist -k vite-react -v 0.0.1", + "prepub": "envision switchOrg apps", + "pub": "envision deploy ./dist -k wallnote -v 0.0.2 -y y", "ev": "npm run build && npm run deploy" }, "stackblitz": { @@ -20,21 +22,40 @@ "license": "MIT", "dependencies": { "@ant-design/icons": "^5.6.1", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.0", "@kevisual/query": "0.0.7-alpha.3", "@kevisual/router": "0.0.6-alpha-5", "@kevisual/system-ui": "^0.0.3", "@kevisual/ui": "^0.0.4-alpha-1", + "@mui/material": "^6.4.5", + "@tiptap/core": "^2.11.5", + "@tiptap/extension-code-block-lowlight": "^2.11.5", + "@tiptap/extension-highlight": "^2.11.5", + "@tiptap/extension-typography": "^2.11.5", + "@tiptap/starter-kit": "^2.11.5", + "@types/lodash-es": "^4.17.12", + "@types/turndown": "^5.0.5", + "@xyflow/react": "^12.4.3", "antd": "^5.24.1", "clsx": "^2.1.1", "dayjs": "^1.11.13", + "highlight.js": "^11.11.1", + "idb": "^8.0.2", + "idb-keyval": "^6.2.1", "immer": "^10.1.1", "lodash-es": "^4.17.21", + "lowlight": "^3.3.0", + "lucide-react": "^0.475.0", + "marked": "^15.0.7", "nanoid": "^5.1.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router": "^7.2.0", "react-router-dom": "^7.2.0", "react-toastify": "^11.0.3", + "tiptap-markdown": "^0.8.10", + "turndown": "^7.2.0", "zustand": "^5.0.3" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 056aff3..982a87f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,12 @@ importers: '@ant-design/icons': specifier: ^5.6.1 version: 5.6.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@emotion/react': + specifier: ^11.14.0 + version: 11.14.0(@types/react@19.0.10)(react@19.0.0) + '@emotion/styled': + specifier: ^11.14.0 + version: 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0) '@kevisual/query': specifier: 0.0.7-alpha.3 version: 0.0.7-alpha.3 @@ -23,6 +29,33 @@ importers: '@kevisual/ui': specifier: ^0.0.4-alpha-1 version: 0.0.4-alpha-1 + '@mui/material': + specifier: ^6.4.5 + version: 6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@tiptap/core': + specifier: ^2.11.5 + version: 2.11.5(@tiptap/pm@2.11.5) + '@tiptap/extension-code-block-lowlight': + specifier: ^2.11.5 + version: 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/extension-code-block@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(highlight.js@11.11.1)(lowlight@3.3.0) + '@tiptap/extension-highlight': + specifier: ^2.11.5 + version: 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-typography': + specifier: ^2.11.5 + version: 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/starter-kit': + specifier: ^2.11.5 + version: 2.11.5 + '@types/lodash-es': + specifier: ^4.17.12 + version: 4.17.12 + '@types/turndown': + specifier: ^5.0.5 + version: 5.0.5 + '@xyflow/react': + specifier: ^12.4.3 + version: 12.4.3(@types/react@19.0.10)(immer@10.1.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) antd: specifier: ^5.24.1 version: 5.24.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -32,12 +65,30 @@ importers: dayjs: specifier: ^1.11.13 version: 1.11.13 + highlight.js: + specifier: ^11.11.1 + version: 11.11.1 + idb: + specifier: ^8.0.2 + version: 8.0.2 + idb-keyval: + specifier: ^6.2.1 + version: 6.2.1 immer: specifier: ^10.1.1 version: 10.1.1 lodash-es: specifier: ^4.17.21 version: 4.17.21 + lowlight: + specifier: ^3.3.0 + version: 3.3.0 + lucide-react: + specifier: ^0.475.0 + version: 0.475.0(react@19.0.0) + marked: + specifier: ^15.0.7 + version: 15.0.7 nanoid: specifier: ^5.1.0 version: 5.1.0 @@ -56,25 +107,22 @@ importers: react-toastify: specifier: ^11.0.3 version: 11.0.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + tiptap-markdown: + specifier: ^0.8.10 + version: 0.8.10(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + turndown: + specifier: ^7.2.0 + version: 7.2.0 zustand: specifier: ^5.0.3 version: 5.0.3(@types/react@19.0.10)(immer@10.1.1)(react@19.0.0)(use-sync-external-store@1.2.2(react@19.0.0)) devDependencies: - '@build/tailwind': - specifier: ^1.0.2-alpha-2 - version: 1.0.2-alpha-2 '@eslint/js': specifier: ^9.20.0 version: 9.20.0 '@kevisual/types': specifier: ^0.0.6 version: 0.0.6 - '@tailwindcss/aspect-ratio': - specifier: ^0.4.2 - version: 0.4.2(tailwindcss@4.0.7) - '@tailwindcss/typography': - specifier: ^0.5.16 - version: 0.5.16(tailwindcss@4.0.7) '@tailwindcss/vite': specifier: ^4.0.7 version: 4.0.7(vite@6.1.1(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(yaml@2.5.1)) @@ -93,9 +141,6 @@ importers: '@vitejs/plugin-react': specifier: ^4.3.4 version: 4.3.4(vite@6.1.1(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(yaml@2.5.1)) - autoprefixer: - specifier: ^10.4.20 - version: 10.4.20(postcss@8.5.3) eslint: specifier: ^9.20.1 version: 9.20.1(jiti@2.4.2) @@ -270,19 +315,70 @@ packages: resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} engines: {node: '>=6.9.0'} - '@build/tailwind@1.0.2-alpha-2': - resolution: {integrity: sha512-64ev/K7CqPOmx2JEpbV1mSlRwdiyD56zf4o4CqY1JYOuh7yPtHeegj7PnAuWoYB2KZuYaQgzilhjH6vwXFe7eQ==} - '@ctrl/tinycolor@3.6.1': resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} engines: {node: '>=10'} + '@emotion/babel-plugin@11.13.5': + resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} + + '@emotion/cache@11.14.0': + resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==} + '@emotion/hash@0.8.0': resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} + + '@emotion/is-prop-valid@1.3.1': + resolution: {integrity: sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==} + + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} + + '@emotion/react@11.14.0': + resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==} + peerDependencies: + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} + + '@emotion/sheet@1.4.0': + resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==} + + '@emotion/styled@11.14.0': + resolution: {integrity: sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==} + peerDependencies: + '@emotion/react': ^11.0.0-rc.0 + '@types/react': '*' + react: '>=16.8.0' + peerDependenciesMeta: + '@types/react': + optional: true + + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} + '@emotion/unitless@0.7.5': resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + '@emotion/use-insertion-effect-with-fallbacks@1.2.0': + resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} + peerDependencies: + react: '>=16.8.0' + + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} + + '@emotion/weak-memoize@0.4.0': + resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} + '@esbuild/aix-ppc64@0.24.2': resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} engines: {node: '>=18'} @@ -520,6 +616,89 @@ packages: '@kevisual/ui@0.0.4-alpha-1': resolution: {integrity: sha512-ow2rp2ijqTJdr1yTgCM4c3xfFwtffOCASpQIkJyxemprZ+juv24BuDQDbt2oLnEudRl/gJJixZ2cZTsmW/EEQw==} + '@mixmark-io/domino@2.2.0': + resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} + + '@mui/core-downloads-tracker@6.4.5': + resolution: {integrity: sha512-zoXvHU1YuoodgMlPS+epP084Pqv9V+Vg+5IGv9n/7IIFVQ2nkTngYHYxElCq8pdTTbDcgji+nNh0lxri2abWgA==} + + '@mui/material@6.4.5': + resolution: {integrity: sha512-5eyEgSXocIeV1JkXs8mYyJXU0aFyXZIWI5kq2g/mCnIgJe594lkOBNAKnCIaGVfQTu2T6TTEHF8/hHIqpiIRGA==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@emotion/react': ^11.5.0 + '@emotion/styled': ^11.3.0 + '@mui/material-pigment-css': ^6.4.3 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/react': + optional: true + '@emotion/styled': + optional: true + '@mui/material-pigment-css': + optional: true + '@types/react': + optional: true + + '@mui/private-theming@6.4.3': + resolution: {integrity: sha512-7x9HaNwDCeoERc4BoEWLieuzKzXu5ZrhRnEM6AUcRXUScQLvF1NFkTlP59+IJfTbEMgcGg1wWHApyoqcksrBpQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@mui/styled-engine@6.4.3': + resolution: {integrity: sha512-OC402VfK+ra2+f12Gef8maY7Y9n7B6CZcoQ9u7mIkh/7PKwW/xH81xwX+yW+Ak1zBT3HYcVjh2X82k5cKMFGoQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@emotion/react': ^11.4.1 + '@emotion/styled': ^11.3.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/react': + optional: true + '@emotion/styled': + optional: true + + '@mui/system@6.4.3': + resolution: {integrity: sha512-Q0iDwnH3+xoxQ0pqVbt8hFdzhq1g2XzzR4Y5pVcICTNtoCLJmpJS3vI4y/OIM1FHFmpfmiEC2IRIq7YcZ8nsmg==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@emotion/react': ^11.5.0 + '@emotion/styled': ^11.3.0 + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/react': + optional: true + '@emotion/styled': + optional: true + '@types/react': + optional: true + + '@mui/types@7.2.21': + resolution: {integrity: sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@mui/utils@6.4.3': + resolution: {integrity: sha512-jxHRHh3BqVXE9ABxDm+Tc3wlBooYz/4XPa0+4AI+iF38rV1/+btJmSUgG4shDtSWVs/I97aDn5jBCt6SF2Uq2A==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -532,6 +711,9 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@popperjs/core@2.11.8': + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@rc-component/async-validator@5.0.4': resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==} engines: {node: '>=14.x'} @@ -587,6 +769,9 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' + '@remirror/core-constants@3.0.0': + resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} + '@rollup/rollup-android-arm-eabi@4.34.8': resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==} cpu: [arm] @@ -682,11 +867,6 @@ packages: cpu: [x64] os: [win32] - '@tailwindcss/aspect-ratio@0.4.2': - resolution: {integrity: sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==} - peerDependencies: - tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1' - '@tailwindcss/node@4.0.7': resolution: {integrity: sha512-dkFXufkbRB2mu3FPsW5xLAUWJyexpJA+/VtQj18k3SUiJVLdpgzBd1v1gRRcIpEJj7K5KpxBKfOXlZxT3ZZRuA==} @@ -760,16 +940,141 @@ packages: resolution: {integrity: sha512-yr6w5YMgjy+B+zkJiJtIYGXW+HNYOPfRPtSs+aqLnKwdEzNrGv4ZuJh9hYJ3mcA+HMq/K1rtFV+KsEr65S558g==} engines: {node: '>= 10'} - '@tailwindcss/typography@0.5.16': - resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==} - peerDependencies: - tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' - '@tailwindcss/vite@4.0.7': resolution: {integrity: sha512-GYx5sxArfIMtdZCsxfya3S/efMmf4RvfqdiLUozkhmSFBNUFnYVodatpoO/en4/BsOIGvq/RB6HwcTLn9prFnQ==} peerDependencies: vite: ^5.2.0 || ^6 + '@tiptap/core@2.11.5': + resolution: {integrity: sha512-jb0KTdUJaJY53JaN7ooY3XAxHQNoMYti/H6ANo707PsLXVeEqJ9o8+eBup1JU5CuwzrgnDc2dECt2WIGX9f8Jw==} + peerDependencies: + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-blockquote@2.11.5': + resolution: {integrity: sha512-MZfcRIzKRD8/J1hkt/eYv49060GTL6qGR3NY/oTDuw2wYzbQXXLEbjk8hxAtjwNn7G+pWQv3L+PKFzZDxibLuA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-bold@2.11.5': + resolution: {integrity: sha512-OAq03MHEbl7MtYCUzGuwb0VpOPnM0k5ekMbEaRILFU5ZC7cEAQ36XmPIw1dQayrcuE8GZL35BKub2qtRxyC9iA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-bullet-list@2.11.5': + resolution: {integrity: sha512-VXwHlX6A/T6FAspnyjbKDO0TQ+oetXuat6RY1/JxbXphH42nLuBaGWJ6pgy6xMl6XY8/9oPkTNrfJw/8/eeRwA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-code-block-lowlight@2.11.5': + resolution: {integrity: sha512-EIE+mAGsp8C69dI0Yyg+VH1x36rgyPJc93SfA7h4xFF6Oth18z4YhJtiLaZcwCMyOOVs2efApZ0R3/Fnz2VlqA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/extension-code-block': ^2.7.0 + '@tiptap/pm': ^2.7.0 + highlight.js: ^11 + lowlight: ^2 || ^3 + + '@tiptap/extension-code-block@2.11.5': + resolution: {integrity: sha512-ksxMMvqLDlC+ftcQLynqZMdlJT1iHYZorXsXw/n+wuRd7YElkRkd6YWUX/Pq/njFY6lDjKiqFLEXBJB8nrzzBA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-code@2.11.5': + resolution: {integrity: sha512-xOvHevNIQIcCCVn9tpvXa1wBp0wHN/2umbAZGTVzS+AQtM7BTo0tz8IyzwxkcZJaImONcUVYLOLzt2AgW1LltA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-document@2.11.5': + resolution: {integrity: sha512-7I4BRTpIux2a0O2qS3BDmyZ5LGp3pszKbix32CmeVh7lN9dV7W5reDqtJJ9FCZEEF+pZ6e1/DQA362dflwZw2g==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-dropcursor@2.11.5': + resolution: {integrity: sha512-uIN7L3FU0904ec7FFFbndO7RQE/yiON4VzAMhNn587LFMyWO8US139HXIL4O8dpZeYwYL3d1FnDTflZl6CwLlg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-gapcursor@2.11.5': + resolution: {integrity: sha512-kcWa+Xq9cb6lBdiICvLReuDtz/rLjFKHWpW3jTTF3FiP3wx4H8Rs6bzVtty7uOVTfwupxZRiKICAMEU6iT0xrQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-hard-break@2.11.5': + resolution: {integrity: sha512-q9doeN+Yg9F5QNTG8pZGYfNye3tmntOwch683v0CCVCI4ldKaLZ0jG3NbBTq+mosHYdgOH2rNbIORlRRsQ+iYQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-heading@2.11.5': + resolution: {integrity: sha512-x/MV53psJ9baRcZ4k4WjnCUBMt8zCX7mPlKVT+9C/o+DEs/j/qxPLs95nHeQv70chZpSwCQCt93xMmuF0kPoAg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-highlight@2.11.5': + resolution: {integrity: sha512-VBZfT869L9CiTLF8qr+3FBUtJcmlyUTECORNo0ceEiNDg4H6V9uNPwaROMXrWiQCc+DYVCOkx541QrXwNMzxlg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-history@2.11.5': + resolution: {integrity: sha512-b+wOS33Dz1azw6F1i9LFTEIJ/gUui0Jwz5ZvmVDpL2ZHBhq1Ui0/spTT+tuZOXq7Y/uCbKL8Liu4WoedIvhboQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-horizontal-rule@2.11.5': + resolution: {integrity: sha512-3up2r1Du8/5/4ZYzTC0DjTwhgPI3dn8jhOCLu73m5F3OGvK/9whcXoeWoX103hYMnGDxBlfOje71yQuN35FL4A==} + peerDependencies: + '@tiptap/core': ^2.7.0 + '@tiptap/pm': ^2.7.0 + + '@tiptap/extension-italic@2.11.5': + resolution: {integrity: sha512-9VGfb2/LfPhQ6TjzDwuYLRvw0A6VGbaIp3F+5Mql8XVdTBHb2+rhELbyhNGiGVR78CaB/EiKb6dO9xu/tBWSYA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-list-item@2.11.5': + resolution: {integrity: sha512-Mp5RD/pbkfW1vdc6xMVxXYcta73FOwLmblQlFNn/l/E5/X1DUSA4iGhgDDH4EWO3swbs03x2f7Zka/Xoj3+WLg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-ordered-list@2.11.5': + resolution: {integrity: sha512-Cu8KwruBNWAaEfshRQR0yOSaUKAeEwxW7UgbvF9cN/zZuKgK5uZosPCPTehIFCcRe+TBpRtZQh+06f/gNYpYYg==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-paragraph@2.11.5': + resolution: {integrity: sha512-YFBWeg7xu/sBnsDIF/+nh9Arf7R0h07VZMd0id5Ydd2Qe3c1uIZwXxeINVtH0SZozuPIQFAT8ICe9M0RxmE+TA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-strike@2.11.5': + resolution: {integrity: sha512-PVfUiCqrjvsLpbIoVlegSY8RlkR64F1Rr2RYmiybQfGbg+AkSZXDeO0eIrc03//4gua7D9DfIozHmAKv1KN3ow==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-text-style@2.11.5': + resolution: {integrity: sha512-YUmYl0gILSd/u/ZkOmNxjNXVw+mu8fpC2f8G4I4tLODm0zCx09j9DDEJXSrM5XX72nxJQqtSQsCpNKnL0hfeEQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-text@2.11.5': + resolution: {integrity: sha512-Gq1WwyhFpCbEDrLPIHt5A8aLSlf8bfz4jm417c8F/JyU0J5dtYdmx0RAxjnLw1i7ZHE7LRyqqAoS0sl7JHDNSQ==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/extension-typography@2.11.5': + resolution: {integrity: sha512-K+mwkyyH3bhnw8f6dKt0AIIh7ipPPVTY5XiWxm1ZMnS6p7TkXeqSJRU6mT1a47YLX4IGBEMlTQdvDVvJ1hwTjA==} + peerDependencies: + '@tiptap/core': ^2.7.0 + + '@tiptap/pm@2.11.5': + resolution: {integrity: sha512-z9JFtqc5ZOsdQLd9vRnXfTCQ8v5ADAfRt9Nm7SqP6FUHII8E1hs38ACzf5xursmth/VonJYb5+73Pqxk1hGIPw==} + + '@tiptap/starter-kit@2.11.5': + resolution: {integrity: sha512-SLI7Aj2ruU1t//6Mk8f+fqW+18uTqpdfLUJYgwu0CkqBckrkRZYZh6GVLk/02k3H2ki7QkFxiFbZrdbZdng0JA==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -785,26 +1090,88 @@ packages: '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/linkify-it@3.0.5': + resolution: {integrity: sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==} + + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/lodash-es@4.17.12': + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} + + '@types/lodash@4.17.15': + resolution: {integrity: sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==} + + '@types/markdown-it@13.0.9': + resolution: {integrity: sha512-1XPwR0+MgXLWfTn9gCsZ55AHOKW1WN+P9vr0PaQh5aerR9LLQXUbjfEAFhjmEmyoYFWAyuN2Mqkn40MZ4ukjBw==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdurl@1.0.5': + resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + '@types/node-forge@1.3.11': resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} '@types/node@22.13.4': resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==} + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + '@types/prop-types@15.7.14': + resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} + '@types/react-dom@19.0.4': resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==} peerDependencies: '@types/react': ^19.0.0 + '@types/react-transition-group@4.4.12': + resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==} + peerDependencies: + '@types/react': '*' + '@types/react@19.0.10': resolution: {integrity: sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==} + '@types/turndown@5.0.5': + resolution: {integrity: sha512-TL2IgGgc7B5j78rIccBtlYAnkuv8nUQqhQc+DSYV5j9Be9XOcm/SKOVRuA47xAVI3680Tk9B1d8flK2GWT2+4w==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@typescript-eslint/eslint-plugin@8.24.1': resolution: {integrity: sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -864,6 +1231,15 @@ packages: peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + '@xyflow/react@12.4.3': + resolution: {integrity: sha512-oO50TIY4rbgOURK5pmvL4LwLOQdh6YkvrvOBZPBedltJ1TINCRp0FiyYKfYhLnaDcW8/aayvGtFpUcSkPQxpGg==} + peerDependencies: + react: '>=17' + react-dom: '>=17' + + '@xyflow/system@0.0.51': + resolution: {integrity: sha512-cYnuM3oWQQjx2Rdz0LdZCnbUaWZdZDiik20kPDYsa5SIlq++ZDIcKiDF6a93ncfMv9Ej5GWfDkouE7bObrdRqQ==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -890,12 +1266,9 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - autoprefixer@10.4.20: - resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -910,11 +1283,6 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.23.3: - resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - browserslist@4.24.2: resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -924,9 +1292,6 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001660: - resolution: {integrity: sha512-GacvNTTuATm26qC74pt+ad1fW15mlQ/zuTzzY1ZoIzECTP8HURDfF43kNxPgf7H1jmelCBQTTbBNxdSXOA7Bqg==} - caniuse-lite@1.0.30001684: resolution: {integrity: sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==} @@ -934,6 +1299,9 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + classcat@5.0.5: + resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -954,6 +1322,9 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -964,18 +1335,58 @@ packages: copy-to-clipboard@3.3.3: resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} @@ -991,13 +1402,20 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + detect-libc@1.0.3: resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} engines: {node: '>=0.10'} hasBin: true - electron-to-chromium@1.5.20: - resolution: {integrity: sha512-74mdl6Fs1HHzK9SUX4CKFxAtAe3nUns48y79TskHNAG6fGOlLfyKA4j855x+0b5u8rWJIrlaG9tcTPstMlwjIw==} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dom-helpers@5.2.1: + resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} electron-to-chromium@1.5.65: resolution: {integrity: sha512-PWVzBjghx7/wop6n22vS2MLU8tKGd4Q91aCEGhG/TYmW6PP5OcSXcdnxTe1NNt0T66N8D6jxh4kC8UsdzOGaIw==} @@ -1006,6 +1424,13 @@ packages: resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} engines: {node: '>=10.13.0'} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + esbuild@0.24.2: resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} engines: {node: '>=18'} @@ -1096,6 +1521,9 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1107,14 +1535,14 @@ packages: flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -1149,6 +1577,23 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + highlight.js@11.11.1: + resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} + engines: {node: '>=12.0.0'} + + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + + idb-keyval@6.2.1: + resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==} + + idb@8.0.2: + resolution: {integrity: sha512-CX70rYhx7GDDQzwwQMDwF6kDRQi5vVs6khHUumDrMecBylKkwvZ8HWvKV08AGb7VbpoGCWUQ4aHzNDgoUiOIUg==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1167,6 +1612,13 @@ packages: inline-style-parser@0.2.4: resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1201,6 +1653,9 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -1286,6 +1741,12 @@ packages: resolution: {integrity: sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q==} engines: {node: '>= 12.0.0'} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1293,18 +1754,39 @@ packages: lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - lodash.castarray@4.4.0: - resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} - - lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lowlight@3.3.0: + resolution: {integrity: sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.475.0: + resolution: {integrity: sha512-NJzvVu1HwFVeZ+Gwq2q00KygM1aBhy/ZrhY9FsAgJtpB+E4R7uxRk9M2iKvHa6/vNxZydIB59htha4c2vvwvVg==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + markdown-it-task-lists@2.1.1: + resolution: {integrity: sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + marked@15.0.7: + resolution: {integrity: sha512-dgLIeKGLx5FwziAnsk4ONoGwHwGPJzselimvlVskE9XLN4Orv9u2VA3GWw/lYUqjfA0rUT/6fqKwfZJapP9BEg==} + engines: {node: '>= 18'} + hasBin: true + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1343,14 +1825,17 @@ packages: node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} - normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -1363,6 +1848,10 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1371,10 +1860,17 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-to-regexp@8.2.0: resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} engines: {node: '>=16'} + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + picocolors@1.1.0: resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} @@ -1385,13 +1881,6 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - postcss-selector-parser@6.0.10: - resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} - engines: {node: '>=4'} - - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.3: resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} engines: {node: ^10 || ^12 || >=14} @@ -1400,6 +1889,71 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + prosemirror-changeset@2.2.1: + resolution: {integrity: sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==} + + prosemirror-collab@1.3.1: + resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + + prosemirror-commands@1.7.0: + resolution: {integrity: sha512-6toodS4R/Aah5pdsrIwnTYPEjW70SlO5a66oo5Kk+CIrgJz3ukOoS+FYDGqvQlAX5PxoGWDX1oD++tn5X3pyRA==} + + prosemirror-dropcursor@1.8.1: + resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==} + + prosemirror-gapcursor@1.3.2: + resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==} + + prosemirror-history@1.4.1: + resolution: {integrity: sha512-2JZD8z2JviJrboD9cPuX/Sv/1ChFng+xh2tChQ2X4bB2HeK+rra/bmJ3xGntCcjhOqIzSDG6Id7e8RJ9QPXLEQ==} + + prosemirror-inputrules@1.4.0: + resolution: {integrity: sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==} + + prosemirror-keymap@1.2.2: + resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==} + + prosemirror-markdown@1.13.1: + resolution: {integrity: sha512-Sl+oMfMtAjWtlcZoj/5L/Q39MpEnVZ840Xo330WJWUvgyhNmLBLN7MsHn07s53nG/KImevWHSE6fEj4q/GihHw==} + + prosemirror-menu@1.2.4: + resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==} + + prosemirror-model@1.24.1: + resolution: {integrity: sha512-YM053N+vTThzlWJ/AtPtF1j0ebO36nvbmDy4U7qA2XQB8JVaQp1FmB9Jhrps8s+z+uxhhVTny4m20ptUvhk0Mg==} + + prosemirror-schema-basic@1.2.3: + resolution: {integrity: sha512-h+H0OQwZVqMon1PNn0AG9cTfx513zgIG2DY00eJ00Yvgb3UD+GQ/VlWW5rcaxacpCGT1Yx8nuhwXk4+QbXUfJA==} + + prosemirror-schema-list@1.5.0: + resolution: {integrity: sha512-gg1tAfH1sqpECdhIHOA/aLg2VH3ROKBWQ4m8Qp9mBKrOxQRW61zc+gMCI8nh22gnBzd1t2u1/NPLmO3nAa3ssg==} + + prosemirror-state@1.4.3: + resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==} + + prosemirror-tables@1.6.4: + resolution: {integrity: sha512-TkDY3Gw52gRFRfRn2f4wJv5WOgAOXLJA2CQJYIJ5+kdFbfj3acR4JUW6LX2e1hiEBiUwvEhzH5a3cZ5YSztpIA==} + + prosemirror-trailing-node@3.0.0: + resolution: {integrity: sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==} + peerDependencies: + prosemirror-model: ^1.22.1 + prosemirror-state: ^1.4.2 + prosemirror-view: ^1.33.8 + + prosemirror-transform@1.10.2: + resolution: {integrity: sha512-2iUq0wv2iRoJO/zj5mv8uDUriOHWzXRnOTVgCzSXnktS/2iQRa3UUQwVlkBlYZFtygw6Nh1+X4mGqoYBINn5KQ==} + + prosemirror-view@1.38.0: + resolution: {integrity: sha512-O45kxXQTaP9wPdXhp8TKqCR+/unS/gnfg9Q93svQcB3j0mlp2XSPAmsPefxHADwzC+fbNS404jqRxm3UQaGvgw==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1646,9 +2200,15 @@ packages: peerDependencies: react: ^19.0.0 + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-is@19.0.0: + resolution: {integrity: sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==} + react-refresh@0.14.2: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} @@ -1676,6 +2236,12 @@ packages: react: ^18 || ^19 react-dom: ^18 || ^19 + react-transition-group@4.4.5: + resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} + peerDependencies: + react: '>=16.6.0' + react-dom: '>=16.6.0' + react@19.0.0: resolution: {integrity: sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==} engines: {node: '>=0.10.0'} @@ -1690,6 +2256,11 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -1699,6 +2270,9 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -1736,6 +2310,10 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + string-convert@0.2.1: resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} @@ -1746,6 +2324,9 @@ packages: style-to-object@1.0.8: resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==} + stylis@4.2.0: + resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} + stylis@4.3.4: resolution: {integrity: sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==} @@ -1753,6 +2334,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + tailwind-merge@3.0.1: resolution: {integrity: sha512-AvzE8FmSoXC7nC+oU5GlQJbip2UO7tmOhOfQyOmPhrStOGXHU08j8mZEHZ4BmCqY5dWTCo4ClWkNyRNx1wpT0g==} @@ -1772,6 +2357,11 @@ packages: resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} engines: {node: '>=12.22'} + tiptap-markdown@0.8.10: + resolution: {integrity: sha512-iDVkR2BjAqkTDtFX0h94yVvE2AihCXlF0Q7RIXSJPRSR5I0PA1TMuAg6FHFpmqTn4tPxJ0by0CK7PUMlnFLGEQ==} + peerDependencies: + '@tiptap/core': ^2.0.3 + to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} @@ -1792,6 +2382,9 @@ packages: turbo-stream@2.4.0: resolution: {integrity: sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==} + turndown@7.2.0: + resolution: {integrity: sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -1808,15 +2401,12 @@ packages: engines: {node: '>=14.17'} hasBin: true + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - update-browserslist-db@1.1.0: - resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - update-browserslist-db@1.1.1: resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true @@ -1831,9 +2421,6 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - vite@6.1.1: resolution: {integrity: sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -1874,6 +2461,9 @@ packages: yaml: optional: true + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1898,6 +2488,10 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + yaml@2.5.1: resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==} engines: {node: '>= 14'} @@ -1907,6 +2501,21 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zustand@4.5.6: + resolution: {integrity: sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + zustand@5.0.3: resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==} engines: {node: '>=12.20.0'} @@ -2113,14 +2722,95 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@build/tailwind@1.0.2-alpha-2': {} - '@ctrl/tinycolor@3.6.1': {} + '@emotion/babel-plugin@11.13.5': + dependencies: + '@babel/helper-module-imports': 7.25.9 + '@babel/runtime': 7.26.0 + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/serialize': 1.3.3 + babel-plugin-macros: 3.1.0 + convert-source-map: 1.9.0 + escape-string-regexp: 4.0.0 + find-root: 1.1.0 + source-map: 0.5.7 + stylis: 4.2.0 + transitivePeerDependencies: + - supports-color + + '@emotion/cache@11.14.0': + dependencies: + '@emotion/memoize': 0.9.0 + '@emotion/sheet': 1.4.0 + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + stylis: 4.2.0 + '@emotion/hash@0.8.0': {} + '@emotion/hash@0.9.2': {} + + '@emotion/is-prop-valid@1.3.1': + dependencies: + '@emotion/memoize': 0.9.0 + + '@emotion/memoize@0.9.0': {} + + '@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0)': + dependencies: + '@babel/runtime': 7.26.0 + '@emotion/babel-plugin': 11.13.5 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.0.0) + '@emotion/utils': 1.4.2 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 + transitivePeerDependencies: + - supports-color + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.1.3 + + '@emotion/sheet@1.4.0': {} + + '@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)': + dependencies: + '@babel/runtime': 7.26.0 + '@emotion/babel-plugin': 11.13.5 + '@emotion/is-prop-valid': 1.3.1 + '@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0) + '@emotion/serialize': 1.3.3 + '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.0.0) + '@emotion/utils': 1.4.2 + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 + transitivePeerDependencies: + - supports-color + + '@emotion/unitless@0.10.0': {} + '@emotion/unitless@0.7.5': {} + '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.0.0)': + dependencies: + react: 19.0.0 + + '@emotion/utils@1.4.2': {} + + '@emotion/weak-memoize@0.4.0': {} + '@esbuild/aix-ppc64@0.24.2': optional: true @@ -2293,6 +2983,85 @@ snapshots: lodash-es: 4.17.21 style-to-object: 1.0.8 + '@mixmark-io/domino@2.2.0': {} + + '@mui/core-downloads-tracker@6.4.5': {} + + '@mui/material@6.4.5(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@babel/runtime': 7.26.0 + '@mui/core-downloads-tracker': 6.4.5 + '@mui/system': 6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0) + '@mui/types': 7.2.21(@types/react@19.0.10) + '@mui/utils': 6.4.3(@types/react@19.0.10)(react@19.0.0) + '@popperjs/core': 2.11.8 + '@types/react-transition-group': 4.4.12(@types/react@19.0.10) + clsx: 2.1.1 + csstype: 3.1.3 + prop-types: 15.8.1 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react-is: 19.0.0 + react-transition-group: 4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + optionalDependencies: + '@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0) + '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0) + '@types/react': 19.0.10 + + '@mui/private-theming@6.4.3(@types/react@19.0.10)(react@19.0.0)': + dependencies: + '@babel/runtime': 7.26.0 + '@mui/utils': 6.4.3(@types/react@19.0.10)(react@19.0.0) + prop-types: 15.8.1 + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 + + '@mui/styled-engine@6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)': + dependencies: + '@babel/runtime': 7.26.0 + '@emotion/cache': 11.14.0 + '@emotion/serialize': 1.3.3 + '@emotion/sheet': 1.4.0 + csstype: 3.1.3 + prop-types: 15.8.1 + react: 19.0.0 + optionalDependencies: + '@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0) + '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0) + + '@mui/system@6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)': + dependencies: + '@babel/runtime': 7.26.0 + '@mui/private-theming': 6.4.3(@types/react@19.0.10)(react@19.0.0) + '@mui/styled-engine': 6.4.3(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0) + '@mui/types': 7.2.21(@types/react@19.0.10) + '@mui/utils': 6.4.3(@types/react@19.0.10)(react@19.0.0) + clsx: 2.1.1 + csstype: 3.1.3 + prop-types: 15.8.1 + react: 19.0.0 + optionalDependencies: + '@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0) + '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0) + '@types/react': 19.0.10 + + '@mui/types@7.2.21(@types/react@19.0.10)': + optionalDependencies: + '@types/react': 19.0.10 + + '@mui/utils@6.4.3(@types/react@19.0.10)(react@19.0.0)': + dependencies: + '@babel/runtime': 7.26.0 + '@mui/types': 7.2.21(@types/react@19.0.10) + '@types/prop-types': 15.7.14 + clsx: 2.1.1 + prop-types: 15.8.1 + react: 19.0.0 + react-is: 19.0.0 + optionalDependencies: + '@types/react': 19.0.10 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2305,6 +3074,8 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.1 + '@popperjs/core@2.11.8': {} + '@rc-component/async-validator@5.0.4': dependencies: '@babel/runtime': 7.26.0 @@ -2374,6 +3145,8 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) + '@remirror/core-constants@3.0.0': {} + '@rollup/rollup-android-arm-eabi@4.34.8': optional: true @@ -2431,10 +3204,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.34.8': optional: true - '@tailwindcss/aspect-ratio@0.4.2(tailwindcss@4.0.7)': - dependencies: - tailwindcss: 4.0.7 - '@tailwindcss/node@4.0.7': dependencies: enhanced-resolve: 5.18.1 @@ -2488,14 +3257,6 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.0.7 '@tailwindcss/oxide-win32-x64-msvc': 4.0.7 - '@tailwindcss/typography@0.5.16(tailwindcss@4.0.7)': - dependencies: - lodash.castarray: 4.4.0 - lodash.isplainobject: 4.0.6 - lodash.merge: 4.6.2 - postcss-selector-parser: 6.0.10 - tailwindcss: 4.0.7 - '@tailwindcss/vite@4.0.7(vite@6.1.1(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(yaml@2.5.1))': dependencies: '@tailwindcss/node': 4.0.7 @@ -2504,6 +3265,152 @@ snapshots: tailwindcss: 4.0.7 vite: 6.1.1(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(yaml@2.5.1) + '@tiptap/core@2.11.5(@tiptap/pm@2.11.5)': + dependencies: + '@tiptap/pm': 2.11.5 + + '@tiptap/extension-blockquote@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-bold@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-bullet-list@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-code-block-lowlight@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/extension-code-block@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)(highlight.js@11.11.1)(lowlight@3.3.0)': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + '@tiptap/extension-code-block': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5) + '@tiptap/pm': 2.11.5 + highlight.js: 11.11.1 + lowlight: 3.3.0 + + '@tiptap/extension-code-block@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + '@tiptap/pm': 2.11.5 + + '@tiptap/extension-code@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-document@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-dropcursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + '@tiptap/pm': 2.11.5 + + '@tiptap/extension-gapcursor@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + '@tiptap/pm': 2.11.5 + + '@tiptap/extension-hard-break@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-heading@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-highlight@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-history@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + '@tiptap/pm': 2.11.5 + + '@tiptap/extension-horizontal-rule@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5)': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + '@tiptap/pm': 2.11.5 + + '@tiptap/extension-italic@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-list-item@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-ordered-list@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-paragraph@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-strike@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-text-style@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-text@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/extension-typography@2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + + '@tiptap/pm@2.11.5': + dependencies: + prosemirror-changeset: 2.2.1 + prosemirror-collab: 1.3.1 + prosemirror-commands: 1.7.0 + prosemirror-dropcursor: 1.8.1 + prosemirror-gapcursor: 1.3.2 + prosemirror-history: 1.4.1 + prosemirror-inputrules: 1.4.0 + prosemirror-keymap: 1.2.2 + prosemirror-markdown: 1.13.1 + prosemirror-menu: 1.2.4 + prosemirror-model: 1.24.1 + prosemirror-schema-basic: 1.2.3 + prosemirror-schema-list: 1.5.0 + prosemirror-state: 1.4.3 + prosemirror-tables: 1.6.4 + prosemirror-trailing-node: 3.0.0(prosemirror-model@1.24.1)(prosemirror-state@1.4.3)(prosemirror-view@1.38.0) + prosemirror-transform: 1.10.2 + prosemirror-view: 1.38.0 + + '@tiptap/starter-kit@2.11.5': + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + '@tiptap/extension-blockquote': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-bold': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-bullet-list': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-code': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-code-block': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5) + '@tiptap/extension-document': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-dropcursor': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5) + '@tiptap/extension-gapcursor': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5) + '@tiptap/extension-hard-break': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-heading': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-history': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5) + '@tiptap/extension-horizontal-rule': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5))(@tiptap/pm@2.11.5) + '@tiptap/extension-italic': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-list-item': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-ordered-list': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-paragraph': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-strike': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-text': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/extension-text-style': 2.11.5(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)) + '@tiptap/pm': 2.11.5 + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.25.6 @@ -2527,10 +3434,59 @@ snapshots: '@types/cookie@0.6.0': {} + '@types/d3-color@3.1.3': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + '@types/estree@1.0.6': {} + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/json-schema@7.0.15': {} + '@types/linkify-it@3.0.5': {} + + '@types/linkify-it@5.0.0': {} + + '@types/lodash-es@4.17.12': + dependencies: + '@types/lodash': 4.17.15 + + '@types/lodash@4.17.15': {} + + '@types/markdown-it@13.0.9': + dependencies: + '@types/linkify-it': 3.0.5 + '@types/mdurl': 1.0.5 + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdurl@1.0.5': {} + + '@types/mdurl@2.0.0': {} + '@types/node-forge@1.3.11': dependencies: '@types/node': 22.13.4 @@ -2539,14 +3495,26 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/parse-json@4.0.2': {} + + '@types/prop-types@15.7.14': {} + '@types/react-dom@19.0.4(@types/react@19.0.10)': dependencies: '@types/react': 19.0.10 + '@types/react-transition-group@4.4.12(@types/react@19.0.10)': + dependencies: + '@types/react': 19.0.10 + '@types/react@19.0.10': dependencies: csstype: 3.1.3 + '@types/turndown@5.0.5': {} + + '@types/unist@3.0.3': {} + '@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3))(eslint@9.20.1(jiti@2.4.2))(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -2639,6 +3607,27 @@ snapshots: transitivePeerDependencies: - supports-color + '@xyflow/react@12.4.3(@types/react@19.0.10)(immer@10.1.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + '@xyflow/system': 0.0.51 + classcat: 5.0.5 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + zustand: 4.5.6(@types/react@19.0.10)(immer@10.1.1)(react@19.0.0) + transitivePeerDependencies: + - '@types/react' + - immer + + '@xyflow/system@0.0.51': + dependencies: + '@types/d3-drag': 3.0.7 + '@types/d3-selection': 3.0.11 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + d3-drag: 3.0.0 + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 @@ -2716,15 +3705,11 @@ snapshots: argparse@2.0.1: {} - autoprefixer@10.4.20(postcss@8.5.3): + babel-plugin-macros@3.1.0: dependencies: - browserslist: 4.23.3 - caniuse-lite: 1.0.30001660 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.1.0 - postcss: 8.5.3 - postcss-value-parser: 4.2.0 + '@babel/runtime': 7.26.0 + cosmiconfig: 7.1.0 + resolve: 1.22.10 balanced-match@1.0.2: {} @@ -2741,13 +3726,6 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.23.3: - dependencies: - caniuse-lite: 1.0.30001660 - electron-to-chromium: 1.5.20 - node-releases: 2.0.18 - update-browserslist-db: 1.1.0(browserslist@4.23.3) - browserslist@4.24.2: dependencies: caniuse-lite: 1.0.30001684 @@ -2757,8 +3735,6 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001660: {} - caniuse-lite@1.0.30001684: {} chalk@4.1.2: @@ -2766,6 +3742,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + classcat@5.0.5: {} + classnames@2.5.1: {} clsx@2.1.1: {} @@ -2780,6 +3758,8 @@ snapshots: concat-map@0.0.1: {} + convert-source-map@1.9.0: {} + convert-source-map@2.0.0: {} cookie@1.0.2: {} @@ -2788,16 +3768,60 @@ snapshots: dependencies: toggle-selection: 1.0.6 + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + + crelt@1.0.6: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - cssesc@3.0.0: {} - csstype@3.1.3: {} + d3-color@3.1.0: {} + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-ease@3.0.1: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-selection@3.0.0: {} + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + dayjs@1.11.13: {} debug@4.3.7: @@ -2806,9 +3830,18 @@ snapshots: deep-is@0.1.4: {} + dequal@2.0.3: {} + detect-libc@1.0.3: {} - electron-to-chromium@1.5.20: {} + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dom-helpers@5.2.1: + dependencies: + '@babel/runtime': 7.26.0 + csstype: 3.1.3 electron-to-chromium@1.5.65: {} @@ -2817,6 +3850,12 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.2.1 + entities@4.5.0: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + esbuild@0.24.2: optionalDependencies: '@esbuild/aix-ppc64': 0.24.2 @@ -2951,6 +3990,8 @@ snapshots: dependencies: to-regex-range: 5.0.1 + find-root@1.1.0: {} + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -2963,11 +4004,11 @@ snapshots: flatted@3.3.1: {} - fraction.js@4.3.7: {} - fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + gensync@1.0.0-beta.2: {} glob-parent@5.1.2: @@ -2990,6 +4031,20 @@ snapshots: has-flag@4.0.0: {} + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + highlight.js@11.11.1: {} + + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + + idb-keyval@6.2.1: {} + + idb@8.0.2: {} + ignore@5.3.2: {} immer@10.1.1: {} @@ -3003,6 +4058,12 @@ snapshots: inline-style-parser@0.2.4: {} + is-arrayish@0.2.1: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + is-extglob@2.1.1: {} is-glob@4.0.3: @@ -3025,6 +4086,8 @@ snapshots: json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -3089,22 +4152,53 @@ snapshots: lightningcss-win32-arm64-msvc: 1.29.1 lightningcss-win32-x64-msvc: 1.29.1 + lines-and-columns@1.2.4: {} + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 lodash-es@4.17.21: {} - lodash.castarray@4.4.0: {} - - lodash.isplainobject@4.0.6: {} - lodash.merge@4.6.2: {} + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lowlight@3.3.0: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + highlight.js: 11.11.1 + lru-cache@5.1.1: dependencies: yallist: 3.1.1 + lucide-react@0.475.0(react@19.0.0): + dependencies: + react: 19.0.0 + + markdown-it-task-lists@2.1.1: {} + + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + marked@15.0.7: {} + + mdurl@2.0.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -3132,7 +4226,7 @@ snapshots: node-releases@2.0.18: {} - normalize-range@0.1.2: {} + object-assign@4.1.1: {} optionator@0.9.4: dependencies: @@ -3143,6 +4237,8 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + orderedmap@2.1.1: {} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -3155,25 +4251,29 @@ snapshots: dependencies: callsites: 3.1.0 + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + path-exists@4.0.0: {} path-key@3.1.1: {} + path-parse@1.0.7: {} + path-to-regexp@8.2.0: {} + path-type@4.0.0: {} + picocolors@1.1.0: {} picocolors@1.1.1: {} picomatch@2.3.1: {} - postcss-selector-parser@6.0.10: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss-value-parser@4.2.0: {} - postcss@8.5.3: dependencies: nanoid: 3.3.8 @@ -3182,6 +4282,117 @@ snapshots: prelude-ls@1.2.1: {} + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + prosemirror-changeset@2.2.1: + dependencies: + prosemirror-transform: 1.10.2 + + prosemirror-collab@1.3.1: + dependencies: + prosemirror-state: 1.4.3 + + prosemirror-commands@1.7.0: + dependencies: + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + + prosemirror-dropcursor@1.8.1: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.38.0 + + prosemirror-gapcursor@1.3.2: + dependencies: + prosemirror-keymap: 1.2.2 + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-view: 1.38.0 + + prosemirror-history@1.4.1: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.38.0 + rope-sequence: 1.3.4 + + prosemirror-inputrules@1.4.0: + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + + prosemirror-keymap@1.2.2: + dependencies: + prosemirror-state: 1.4.3 + w3c-keyname: 2.2.8 + + prosemirror-markdown@1.13.1: + dependencies: + '@types/markdown-it': 14.1.2 + markdown-it: 14.1.0 + prosemirror-model: 1.24.1 + + prosemirror-menu@1.2.4: + dependencies: + crelt: 1.0.6 + prosemirror-commands: 1.7.0 + prosemirror-history: 1.4.1 + prosemirror-state: 1.4.3 + + prosemirror-model@1.24.1: + dependencies: + orderedmap: 2.1.1 + + prosemirror-schema-basic@1.2.3: + dependencies: + prosemirror-model: 1.24.1 + + prosemirror-schema-list@1.5.0: + dependencies: + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + + prosemirror-state@1.4.3: + dependencies: + prosemirror-model: 1.24.1 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.38.0 + + prosemirror-tables@1.6.4: + dependencies: + prosemirror-keymap: 1.2.2 + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + prosemirror-view: 1.38.0 + + prosemirror-trailing-node@3.0.0(prosemirror-model@1.24.1)(prosemirror-state@1.4.3)(prosemirror-view@1.38.0): + dependencies: + '@remirror/core-constants': 3.0.0 + escape-string-regexp: 4.0.0 + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-view: 1.38.0 + + prosemirror-transform@1.10.2: + dependencies: + prosemirror-model: 1.24.1 + + prosemirror-view@1.38.0: + dependencies: + prosemirror-model: 1.24.1 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.10.2 + + punycode.js@2.3.1: {} + punycode@2.3.1: {} queue-microtask@1.2.3: {} @@ -3517,8 +4728,12 @@ snapshots: react: 19.0.0 scheduler: 0.25.0 + react-is@16.13.1: {} + react-is@18.3.1: {} + react-is@19.0.0: {} + react-refresh@0.14.2: {} react-router-dom@7.2.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0): @@ -3543,6 +4758,15 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) + react-transition-group@4.4.5(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + dependencies: + '@babel/runtime': 7.26.0 + dom-helpers: 5.2.1 + loose-envify: 1.4.0 + prop-types: 15.8.1 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + react@19.0.0: {} regenerator-runtime@0.14.1: {} @@ -3551,6 +4775,12 @@ snapshots: resolve-from@4.0.0: {} + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + reusify@1.0.4: {} rollup@4.34.8: @@ -3578,6 +4808,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.34.8 fsevents: 2.3.3 + rope-sequence@1.3.4: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -3607,6 +4839,8 @@ snapshots: source-map-js@1.2.1: {} + source-map@0.5.7: {} + string-convert@0.2.1: {} strip-json-comments@3.1.1: {} @@ -3615,12 +4849,16 @@ snapshots: dependencies: inline-style-parser: 0.2.4 + stylis@4.2.0: {} + stylis@4.3.4: {} supports-color@7.2.0: dependencies: has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + tailwind-merge@3.0.1: {} tailwindcss-animate@1.0.7(tailwindcss@4.0.7): @@ -3633,6 +4871,14 @@ snapshots: throttle-debounce@5.0.2: {} + tiptap-markdown@0.8.10(@tiptap/core@2.11.5(@tiptap/pm@2.11.5)): + dependencies: + '@tiptap/core': 2.11.5(@tiptap/pm@2.11.5) + '@types/markdown-it': 13.0.9 + markdown-it: 14.1.0 + markdown-it-task-lists: 2.1.1 + prosemirror-markdown: 1.13.1 + to-fast-properties@2.0.0: {} to-regex-range@5.0.1: @@ -3647,6 +4893,10 @@ snapshots: turbo-stream@2.4.0: {} + turndown@7.2.0: + dependencies: + '@mixmark-io/domino': 2.2.0 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -3663,13 +4913,9 @@ snapshots: typescript@5.7.3: {} - undici-types@6.20.0: {} + uc.micro@2.1.0: {} - update-browserslist-db@1.1.0(browserslist@4.23.3): - dependencies: - browserslist: 4.23.3 - escalade: 3.2.0 - picocolors: 1.1.0 + undici-types@6.20.0: {} update-browserslist-db@1.1.1(browserslist@4.24.2): dependencies: @@ -3684,9 +4930,6 @@ snapshots: use-sync-external-store@1.2.2(react@19.0.0): dependencies: react: 19.0.0 - optional: true - - util-deprecate@1.0.2: {} vite@6.1.1(@types/node@22.13.4)(jiti@2.4.2)(lightningcss@1.29.1)(yaml@2.5.1): dependencies: @@ -3700,6 +4943,8 @@ snapshots: lightningcss: 1.29.1 yaml: 2.5.1 + w3c-keyname@2.2.8: {} + which@2.0.2: dependencies: isexe: 2.0.0 @@ -3710,11 +4955,21 @@ snapshots: yallist@3.1.1: {} + yaml@1.10.2: {} + yaml@2.5.1: optional: true yocto-queue@0.1.0: {} + zustand@4.5.6(@types/react@19.0.10)(immer@10.1.1)(react@19.0.0): + dependencies: + use-sync-external-store: 1.2.2(react@19.0.0) + optionalDependencies: + '@types/react': 19.0.10 + immer: 10.1.1 + react: 19.0.0 + zustand@5.0.3(@types/react@19.0.10)(immer@10.1.1)(react@19.0.0)(use-sync-external-store@1.2.2(react@19.0.0)): optionalDependencies: '@types/react': 19.0.10 diff --git a/src/App.tsx b/src/App.tsx index 5d11d0a..40ed76b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,9 +1,27 @@ +import { Flow } from './pages/wall'; +import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import { Editor } from './pages/editor'; +import { ToastContainer } from 'react-toastify'; +import 'react-toastify/dist/ReactToastify.css'; +import { List } from './pages/wall/pages/List'; +import { Auth } from './modules/layouts/Auth'; + export const App = () => { return ( -
-
-
-
-
+ <> + + + }> + } /> + } /> + + }> + } /> + } /> + + + + + ); }; diff --git a/src/index.css b/src/index.css index ad74ee7..d72c2a8 100644 --- a/src/index.css +++ b/src/index.css @@ -1,7 +1,35 @@ -@import "tailwindcss"; +@import 'tailwindcss'; +@import './pages/wall/modules/CustomNode.css'; @layer components { - .test-loading { - @apply w-20 h-20 bg-gray-300 rounded-full animate-spin; + .node-editor { + @apply w-20 h-20 bg-gray-300 bg-white; + } +} + +html, +body { + overflow: hidden; + margin: 0; + padding: 0; + height: 100%; + width: 100%; +} +body { + font-family: 'Roboto', sans-serif; + background-color: #f5f5f5; + font-size: 16px; +} + +#root { + height: 100%; + width: 100%; +} +.react-flow__attribution { + display: none; +} +.drawer-editor { + .tiptap { + border: unset; } } \ No newline at end of file diff --git a/src/modules/dayjs.ts b/src/modules/dayjs.ts new file mode 100644 index 0000000..1064394 --- /dev/null +++ b/src/modules/dayjs.ts @@ -0,0 +1,11 @@ +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; +dayjs.extend(relativeTime); + +export const formatDate = (date?: string, format = 'YYYY-MM-DD HH:mm:ss') => { + return dayjs(date).format(format); +}; + +export const formatRelativeDate = (date?: string) => { + return dayjs(date).fromNow(); +}; diff --git a/src/modules/layouts/Auth.tsx b/src/modules/layouts/Auth.tsx new file mode 100644 index 0000000..b43aa16 --- /dev/null +++ b/src/modules/layouts/Auth.tsx @@ -0,0 +1,24 @@ +import { useEffect } from 'react'; +import { useUserWallStore } from '../../pages/wall/store/user-wall'; +import { useShallow } from 'zustand/react/shallow'; +import { Outlet } from 'react-router-dom'; + +export const Auth = ({ children, auth = true }: { children?: React.ReactNode; auth?: boolean }) => { + const userStore = useUserWallStore( + useShallow((state) => { + return { user: state.user, queryMe: state.queryMe }; + }), + ); + useEffect(() => { + if (!userStore.user) { + userStore.queryMe(auth); + } + }, []); + if (children) { + if (auth) { + return <>{userStore.user && children}; + } + return <>{children}; + } + return <>{}; +}; diff --git a/src/modules/md2html.ts b/src/modules/md2html.ts new file mode 100644 index 0000000..34db255 --- /dev/null +++ b/src/modules/md2html.ts @@ -0,0 +1,10 @@ +import { marked } from 'marked'; +import TurndownService from 'turndown'; +export const md2html = async (md: string) => { + return marked.parse(md); +}; + +export const html2md = async (html: string) => { + const turndownService = new TurndownService(); + return turndownService.turndown(html); +}; diff --git a/src/modules/message.ts b/src/modules/message.ts new file mode 100644 index 0000000..58fd1a2 --- /dev/null +++ b/src/modules/message.ts @@ -0,0 +1,23 @@ +import { toast, ToastOptions } from 'react-toastify'; + +export const message = { + error: (message: string, options?: ToastOptions) => { + toast.error(message, options); + }, + success: (message: string, options?: ToastOptions) => { + toast.success(message, { + position: 'top-left', + autoClose: 1000, + ...options, + }); + }, + warning: (message: string, options?: ToastOptions) => { + toast.warning(message, options); + }, + info: (message: string, options?: ToastOptions) => { + toast.info(message, options); + }, + default: (message: string, options?: ToastOptions) => { + toast(message, options); + }, +}; diff --git a/src/modules/query.ts b/src/modules/query.ts new file mode 100644 index 0000000..111caf7 --- /dev/null +++ b/src/modules/query.ts @@ -0,0 +1,17 @@ +import { QueryClient } from '@kevisual/query'; +import { modal } from './require-to-login'; +import { message } from './message'; + +export const query = new QueryClient(); + +query.afterResponse = async (res) => { + if (res.code === 401) { + modal.setOpen(true); + } + if (res.code === 403) { + if (!res?.message) { + message.error('Unauthorized'); + } + } + return res; +}; diff --git a/src/modules/require-to-login.ts b/src/modules/require-to-login.ts new file mode 100644 index 0000000..1cb9d0f --- /dev/null +++ b/src/modules/require-to-login.ts @@ -0,0 +1,36 @@ +import { DialogModal } from '@kevisual/system-ui/dist/modal'; +// import '@kevisual/system-ui/dist/modal.css'; + +const content = document.createElement('div'); +const loginUrl = '/root/center/user/login'; +export const redirectToLogin = (open = true) => { + const url = new URL(loginUrl, window.location.href); + url.searchParams.set('redirect', window.location.href); + if (open) { + window.open(url.toString(), '_blank'); + } else { + return url.toString(); + } +}; +content.innerHTML = ` +
+

Token 无效

+

您的登录凭证已失效,请重新登录。

+ 确定 +
+`; +export const modal = DialogModal.render(content, { + id: 'redirect-to-login', + contentStyle: { + width: 'unset', + }, + dialogTitleStyle: { + display: 'none', + padding: '0', + }, + dialogContentStyle: { + padding: '0', + }, + mask: true, + open: false, +}); diff --git a/src/modules/tiptap/editor.ts b/src/modules/tiptap/editor.ts new file mode 100644 index 0000000..77126bf --- /dev/null +++ b/src/modules/tiptap/editor.ts @@ -0,0 +1,98 @@ +import { Editor } from '@tiptap/core'; +import StarterKit from '@tiptap/starter-kit'; +import Highlight from '@tiptap/extension-highlight'; +import Typography from '@tiptap/extension-typography'; +import { Markdown } from 'tiptap-markdown'; + +import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight'; +import { all, createLowlight } from 'lowlight'; +import 'highlight.js/styles/github.css'; +// 根据需要引入的语言支持 +import js from 'highlight.js/lib/languages/javascript'; +import ts from 'highlight.js/lib/languages/typescript'; +import html from 'highlight.js/lib/languages/xml'; +import css from 'highlight.js/lib/languages/css'; +import markdown from 'highlight.js/lib/languages/markdown'; +const lowlight = createLowlight(all); + +// you can also register individual languages +lowlight.register('html', html); +lowlight.register('css', css); +lowlight.register('js', js); +lowlight.register('ts', ts); +lowlight.register('markdown', markdown); + +export class TextEditor { + private editor?: Editor; + + constructor() {} + createEditor(el: HTMLElement, opts?: { markdown?: string; html?: string }) { + if (this.editor) { + this.destroy(); + } + const html = opts?.html || ''; + this.editor = new Editor({ + element: el, // 指定编辑器容器 + extensions: [ + StarterKit, // 使用 StarterKit 包含基础功能 + Highlight, + Typography, + Markdown, + CodeBlockLowlight.extend({ + addKeyboardShortcuts() { + return { + Tab: () => { + const { state, dispatch } = this.editor.view; + const { tr, selection } = state; + const { from, to } = selection; + + // 插入4个空格的缩进 + dispatch(tr.insertText(' ', from, to)); + return true; + }, + 'Shift-Tab': () => { + const { state, dispatch } = this.editor.view; + const { tr, selection } = state; + const { from, to } = selection; + + // 获取当前选中的文本 + const selectedText = state.doc.textBetween(from, to, '\n'); + + // 取消缩进:移除前面的4个空格 + const unindentedText = selectedText.replace(/^ {1,4}/gm, ''); + dispatch(tr.insertText(unindentedText, from, to)); + return true; + }, + }; + }, + }).configure({ + lowlight, + }), + ], + content: html, // 初始化内容 + }); + } + setContent(html: string) { + this.editor?.commands.setContent(html); + } + getHtml() { + return this.editor?.getHTML(); + } + getContent() { + return this.editor?.getText(); + } + onContentChange(callback: (html: string) => void) { + this.editor?.off('update'); // 移除之前的监听 + this.editor?.on('update', () => { + callback(this.editor?.getHTML() || ''); + }); + } + foucus() { + this.editor?.view?.focus?.(); + } + + destroy() { + this.editor?.destroy(); + this.editor = undefined; + } +} diff --git a/src/pages/editor/index.tsx b/src/pages/editor/index.tsx new file mode 100644 index 0000000..26b85a8 --- /dev/null +++ b/src/pages/editor/index.tsx @@ -0,0 +1,32 @@ +import { TextEditor } from '@/modules/tiptap/editor'; +import { useEffect, useRef, useState } from 'react'; +import clsx from 'clsx'; +type EditorProps = { + className?: string; + value?: string; + id?: string; + onChange?: (value: string) => void; +}; +export const Editor = ({ className, value, onChange, id }: EditorProps) => { + const textEditorRef = useRef(null); + const editorRef = useRef(null); + const [mount, setMount] = useState(false); + useEffect(() => { + const editor = new TextEditor(); + textEditorRef.current = editor; + editor.createEditor(editorRef.current!, { html: value }); + editor.onContentChange((content) => { + onChange?.(content); + }); + setMount(true); + return () => { + editor.destroy(); + }; + }, []); + useEffect(() => { + if (textEditorRef.current && id && mount) { + textEditorRef.current.setContent(value || ''); + } + }, [id, mount]); + return
; +}; diff --git a/src/pages/wall/components/Icon.tsx b/src/pages/wall/components/Icon.tsx new file mode 100644 index 0000000..ef96859 --- /dev/null +++ b/src/pages/wall/components/Icon.tsx @@ -0,0 +1,21 @@ +export function ResizeIcon({ className }: { className?: string }) { + return ( + + + + + + + + ); +} diff --git a/src/pages/wall/constants.ts b/src/pages/wall/constants.ts new file mode 100644 index 0000000..0667cd3 --- /dev/null +++ b/src/pages/wall/constants.ts @@ -0,0 +1 @@ +export const BlankNoteText = 'double click to edit'; diff --git a/src/pages/wall/hooks/check-double-click.ts b/src/pages/wall/hooks/check-double-click.ts new file mode 100644 index 0000000..f8240a7 --- /dev/null +++ b/src/pages/wall/hooks/check-double-click.ts @@ -0,0 +1,35 @@ +import { useCallback, useRef } from 'react'; + +export const useCheckDoubleClick = ({ + onPaneDoubleClick, + onPaneClick, +}: { + onPaneDoubleClick?: (e: React.MouseEvent) => void; + onPaneClick?: (e: React.MouseEvent) => void; +}) => { + const lastClickTime = useRef(0); + const clickTimeOut = useRef(null); + + const onCheckPanelDoubleClick = useCallback( + (e: React.MouseEvent) => { + const currentTime = Date.now(); + if (currentTime - lastClickTime.current < 300 && lastClickTime.current !== 0) { + onPaneDoubleClick?.(e); // Use optional chaining to call debounceClick if it's defined + clearTimeout(clickTimeOut.current!); + clickTimeOut.current = null; + lastClickTime.current = 0; // Reset + return; + } else if (lastClickTime.current === 0) { + // First click, setup a timeout to handle single click + lastClickTime.current = currentTime; // Update the last click time here as well + clickTimeOut.current = setTimeout(() => { + onPaneClick?.(e); + lastClickTime.current = 0; // Reset + }, 300); + } + }, + [onPaneDoubleClick, onPaneClick], + ); + + return { onCheckPanelDoubleClick }; +}; diff --git a/src/pages/wall/hooks/tab-node.ts b/src/pages/wall/hooks/tab-node.ts new file mode 100644 index 0000000..2e13547 --- /dev/null +++ b/src/pages/wall/hooks/tab-node.ts @@ -0,0 +1,62 @@ +import { useReactFlow } from '@xyflow/react'; +import { useEffect } from 'react'; + +export const useTabNode = () => { + const reactFlowInstance = useReactFlow(); + useEffect(() => { + const listener = (event: any) => { + if (event.key === 'Tab') { + console.log('tab'); + const nodes = reactFlowInstance.getNodes(); + const selectedNode = nodes.find((node) => node.selected); + if (!selectedNode) return; + // 获取选中的节点 + const { x, y } = selectedNode?.position || { x: 0, y: 0 }; + // 根据nodes的position的x和y进行排序,x小的在前,x相等时,y小的在前 + const newNodes = nodes.sort((a, b) => { + const { x: ax, y: ay } = a.position || { x: 0, y: 0 }; + const { x: bx, y: by } = b.position || { x: 0, y: 0 }; + if (ax < bx) return -1; + if (ax > bx) return 1; + return ay - by; + }); + const nextNode = newNodes.find((node) => { + if (node.id === selectedNode?.id) return false; + const { x: nx, y: ny } = node.position; + if (nx > x) { + return true; + } else if (nx === x) { + if (ny > y) { + return true; + } + } + return false; + }); + if (nextNode) { + const newNodes = nodes.map((node) => { + if (node.id === nextNode.id) { + return { ...node, selected: true }; + } + return { ...node, selected: false }; + }); + reactFlowInstance.setNodes(newNodes); + } else { + const newNodes = nodes.map((node) => { + if (node.id === nodes[0].id) { + return { ...node, selected: true }; + } + return { ...node, selected: false }; + }); + reactFlowInstance.setNodes(newNodes); + } + + event.preventDefault(); + event.stopPropagation(); + } + }; + window.addEventListener('keydown', listener); + return () => { + window.removeEventListener('keydown', listener); + }; + }, [reactFlowInstance]); +}; diff --git a/src/pages/wall/index.tsx b/src/pages/wall/index.tsx new file mode 100644 index 0000000..cdaa1af --- /dev/null +++ b/src/pages/wall/index.tsx @@ -0,0 +1,174 @@ +import { + ReactFlow, + MiniMap, + Controls, + Background, + useNodesState, + Node, + useReactFlow, + ReactFlowProvider, + Panel, + useStoreApi, + useStore, + XYPosition, + NodeChange, +} from '@xyflow/react'; + +import '@xyflow/react/dist/style.css'; +import { useWallStore } from './store/wall'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useCheckDoubleClick } from './hooks/check-double-click'; +import { randomId } from './utils/random'; +import { CustomNodeType } from './modules/CustomNode'; +import Drawer from './modules/Drawer'; +import { message } from '@/modules/message'; +import { useShallow } from 'zustand/react/shallow'; +import { BlankNoteText } from './constants'; +import { Toolbar } from './modules/toolbar/Toolbar'; +import { useUserWallStore } from './store/user-wall'; +import { useNavigate, useParams } from 'react-router-dom'; +import { SaveModal } from './modules/FormDialog'; +import { useTabNode } from './hooks/tab-node'; +import { Button } from '@mui/material'; +type NodeData = { + id: string; + position: XYPosition; + data: any; +}; +export function FlowContent() { + const reactFlowInstance = useReactFlow(); + const [nodes, setNodes, onNodesChange] = useNodesState([]); + const wallStore = useWallStore((state) => state); + const store = useStore((state) => state); + const [mount, setMount] = useState(false); + const _onNodesChange = useCallback((changes: NodeChange[]) => { + const [change] = changes; + if (change.type === 'position' && change.dragging === false) { + // console.log('position changes', change); + getNewNodes(); + } + onNodesChange(changes); + }, []); + useEffect(() => { + setNodes(wallStore.nodes); + setMount(true); + return () => { + setMount(false); + }; + }, [wallStore.nodes]); + const onNodeDoubleClick = (event, node) => { + wallStore.setOpen(true); + wallStore.setSelectedNode(node); + }; + const getNewNodes = () => { + const nodes = reactFlowInstance.getNodes(); + wallStore.saveNodes(nodes); + }; + useEffect(() => { + if (mount) { + // console.log('nodes', nodes); + } + }, [nodes, mount]); + useTabNode(); + // 添加新节点的函数 + const onPaneDoubleClick = (event) => { + // 计算节点位置 + const x = event.clientX; + const y = event.clientY; + const postion = reactFlowInstance.screenToFlowPosition({ x, y }); + const newNode = { + id: randomId(), // 确保每个节点有唯一的ID + type: 'wall', // 节点类型 + position: postion, // 使用事件的客户端坐标 + data: { html: BlankNoteText }, + }; + setNodes((nds) => { + const newNodes = nds.concat(newNode); + getNewNodes(); + return newNodes; + }); + message.success('添加节点成功'); + setTimeout(() => { + wallStore.setSelectedNode(newNode); + wallStore.setOpen(true); + }, 200); + }; + const hasFoucedNode = useMemo(() => { + return !!store.nodes.find((node) => node.selected); + }, [store.nodes]); + const { onCheckPanelDoubleClick } = useCheckDoubleClick({ + onPaneDoubleClick, + }); + return ( + + + + + + + + + + + + + ); +} +export const Flow = ({ checkLogin = true }: { checkLogin?: boolean }) => { + const { id } = useParams(); + const navigate = useNavigate(); + const wallStore = useWallStore( + useShallow((state) => { + return { + loaded: state.loaded, + init: state.init, + }; + }), + ); + + useEffect(() => { + wallStore.init(id); + console.log('checkLogin', checkLogin, id); + }, [id, checkLogin]); + + if (!wallStore.loaded) { + return
loading...
; + } else if (wallStore.loaded === 'error') { + return ( +
+
获取失败,请稍后刷新重试,或者转到首页
+ +
+ ); + } + return ( + + + + ); +}; +export const FlowStatus = () => { + const { nodes } = useWallStore(); + const reactFlow = useReactFlow(); + const flowStore = useStore((state) => state); + return ( +
+
节点数量: {nodes.length}
+
+ ); +}; diff --git a/src/pages/wall/modules/CustomNode.css b/src/pages/wall/modules/CustomNode.css new file mode 100644 index 0000000..344918b --- /dev/null +++ b/src/pages/wall/modules/CustomNode.css @@ -0,0 +1,149 @@ +@import 'tailwindcss'; + +@layer components { + .node-editor { + @apply w-full h-full bg-white; + > div { + @apply w-full h-full outline-none; + } + } + .no-scrollbar::-webkit-scrollbar { + display: none; + } + .scrollbar::-webkit-scrollbar { + display: block; + width: 2px; + height: 2px; + } + .scrollbar::-webkit-scrollbar-thumb { + background-color: #ccc; + border-radius: 2px; + } + .scrollbar::-webkit-scrollbar-thumb:horizontal { + background-color: #ccc; + border-radius: 2px; + } +} + +:root { + --purple-light: #e0e0ff; /* 默认浅紫色背景 */ + --black: #000000; /* 默认黑色 */ + --white: #ffffff; /* 默认白色 */ + --gray-3: #d3d3d3; /* 默认灰色3 */ + --gray-2: #e5e5e5; /* 默认灰色2 */ +} +.tiptap-preview { + .tiptap { + margin: 0; + padding: 0.5rem; + border: unset; + } +} +.tiptap { + margin: 0.5rem 1rem; + padding: 0.5rem; + border-radius: 5px; + border: 1px solid #ccc; +} +/* Basic editor styles */ +.tiptap:first-child { + margin-top: 0; +} + +/* List styles */ +.tiptap ul, +.tiptap ol { + padding: 0 1rem; + margin: 1.25rem 1rem 1.25rem 0.4rem; +} + +.tiptap ul li p, +.tiptap ol li p { + margin-top: 0.25em; + margin-bottom: 0.25em; +} + +/* Heading styles */ +.tiptap h1, +.tiptap h2, +.tiptap h3, +.tiptap h4, +.tiptap h5, +.tiptap h6 { + line-height: 1.1; + margin-top: 2.5rem; + text-wrap: pretty; +} + +.tiptap h1, +.tiptap h2 { + /* margin-top: 3.5rem; */ + margin-top: 1rem; + margin-bottom: .5rem; +} + +.tiptap h1 { + font-size: 1.4rem; + font-weight: 800; +} + +.tiptap h2 { + font-size: 1.2rem; + font-weight: 600; +} + +.tiptap h3 { + font-size: 1.1rem; + font-weight: 500; +} + +.tiptap h4, +.tiptap h5, +.tiptap h6 { + font-size: 1rem; +} + +/* Code and preformatted text styles */ +.tiptap code { + background-color: var(--purple-light); + border-radius: 0.4rem; + color: var(--black); + font-size: 0.85rem; + padding: 0.25em 0.3em; +} + +.tiptap pre { + border: 1px solid #ccc; + /* background: var(--black); */ + border-radius: 0.5rem; + /* color: var(--white); */ + font-family: 'JetBrainsMono', monospace; + margin: 1.5rem 0; + padding: 0.75rem 1rem; +} + +.tiptap pre code { + background: none; + color: inherit; + font-size: 0.8rem; + padding: 0; +} + +.tiptap mark { + background-color: #FAF594; + border-radius: 0.4rem; + box-decoration-break: clone; + padding: 0.1rem 0.3rem; +} + +.tiptap blockquote { + border-left: 3px solid var(--gray-3); + margin: 1.5rem 0; + padding-left: 1rem; +} + +.tiptap hr { + border: none; + border-top: 1px solid var(--gray-2); + margin: 2rem 0; +} diff --git a/src/pages/wall/modules/CustomNode.tsx b/src/pages/wall/modules/CustomNode.tsx new file mode 100644 index 0000000..c716046 --- /dev/null +++ b/src/pages/wall/modules/CustomNode.tsx @@ -0,0 +1,150 @@ +import { useRef, memo, useEffect, useMemo, useState } from 'react'; +import clsx from 'clsx'; +import { NodeResizer, useStore } from '@xyflow/react'; +import { useWallStore } from '../store/wall'; +import { useShallow } from 'zustand/react/shallow'; +import { toast } from 'react-toastify'; +import { message } from '@/modules/message'; +import hljs from 'highlight.js'; +import { Edit } from 'lucide-react'; +export type WallData> = { + html: string; + width?: number; + height?: number; + [key: string]: any; +} & T; +const ShowContent = (props: { data: WallData; selected: boolean }) => { + const html = props.data.html; + const selected = props.selected; + const showRef = useRef(null); + if (!html) return
; + const [highlightHtml, setHighlightHtml] = useState(''); + const highlight = async (html: string) => { + const _html = html.replace(/
([\s\S]*?)<\/code><\/pre>/g, (match, p1, p2) => {
+      return `
${hljs.highlight(p2, { language: p1 }).value}
`; + }); + return _html; + }; + useEffect(() => { + highlight(html).then((res) => { + setHighlightHtml(res); + }); + }, [html]); + + return ( +
+ ); +}; + +export const CustomNode = (props: { id: string; data: WallData; selected: boolean }) => { + const data = props.data; + const contentRef = useRef(null); + const selected = props.selected; + const wallStore = useWallStore( + useShallow((state) => { + return { + setOpen: state.setOpen, + setSelectedNode: state.setSelectedNode, + saveNodes: state.saveNodes, + }; + }), + ); + const store = useStore((state) => { + return { + updateWallRect: (id: string, rect: { width: number; height: number }) => { + const nodes = state.nodes.map((node) => { + if (node.id === id) { + node.data.width = rect.width; + node.data.height = rect.height; + } + return node; + }); + state.setNodes(nodes); + wallStore.saveNodes(nodes); + }, + getNode: (id: string) => { + return state.nodes.find((node) => node.id === id); + }, + deleteNode: (id: string) => { + const nodes = state.nodes.filter((node) => node.id !== id); + state.setNodes(nodes); + wallStore.saveNodes(nodes); + }, + }; + }); + useEffect(() => { + if (selected) { + const handleDelete = (e: KeyboardEvent) => { + if (e.key === 'Delete') { + store.deleteNode(props.id); + } + }; + window.addEventListener('keydown', handleDelete); + return () => window.removeEventListener('keydown', handleDelete); + } + }, [selected]); + const width = data.width || 100; + const height = data.height || 100; + const style: React.CSSProperties = {}; + style.width = width; + style.height = height; + const showOpen = () => { + const node = store.getNode(props.id); + if (node) { + wallStore.setOpen(true); + wallStore.setSelectedNode(node); + } else { + message.error('节点不存在'); + } + }; + return ( + <> +
{ + showOpen(); + // e.stopPropagation(); + e.preventDefault(); + }} + className={clsx('w-full h-full border relative border-gray-300 min-w-[100px] min-h-[50px] tiptap-preview')} + style={style}> + +
+
+ +
+ {}} + isVisible={props.selected} + onResizeEnd={(e) => { + const parent = contentRef.current?.parentElement; + if (!parent) return; + const width = parent.style.width; + const height = parent.style.height; + const widthNum = parseInt(width); + const heightNum = parseInt(height); + if (!heightNum || !widthNum) return; + store.updateWallRect(props.id, { width: widthNum, height: heightNum }); + }} + /> + + ); +}; +export const WallNoteNode = memo(CustomNode); +export const CustomNodeType = { + wall: WallNoteNode, +}; diff --git a/src/pages/wall/modules/Drawer.tsx b/src/pages/wall/modules/Drawer.tsx new file mode 100644 index 0000000..e7eefab --- /dev/null +++ b/src/pages/wall/modules/Drawer.tsx @@ -0,0 +1,106 @@ +import { useWallStore } from '../store/wall'; // 确保导入正确的路径 +import clsx from 'clsx'; +import { X } from 'lucide-react'; // 导入 Close 图标 +import { Editor } from '@/pages/editor'; +import { useEffect, useState } from 'react'; +import { useStore, useStoreApi } from '@xyflow/react'; +import { BlankNoteText } from '../constants'; +import { message } from '@/modules/message'; +import { useShallow } from 'zustand/react/shallow'; +import { isMac } from '../utils/is-mac'; +const Drawer = () => { + const { open, setOpen, selectedNode, setSelectedNode, editValue, setEditValue } = useWallStore( + useShallow((state) => ({ + open: state.open, + setOpen: state.setOpen, + selectedNode: state.selectedNode, + setSelectedNode: state.setSelectedNode, + editValue: state.editValue, + setEditValue: state.setEditValue, + })), + ); + const store = useStore((state) => state); + const storeApi = useStoreApi(); + useEffect(() => { + if (open && selectedNode) { + setEditValue(selectedNode?.data.html); + } + }, [open, selectedNode]); + useEffect(() => { + return () => { + setOpen(false); + setSelectedNode(null); + }; + }, []); + const listener = async (e: KeyboardEvent) => { + if (e.key === 'Escape') { + setOpen(false); + } + + const systemKey = e.metaKey || e.ctrlKey; + + // mac command+s windows ctrl+s + if (systemKey && e.key === 's') { + onSave(); + e.preventDefault(); + e.stopPropagation(); + } + }; + useEffect(() => { + window.addEventListener('keydown', listener); + return () => { + window.removeEventListener('keydown', listener); + }; + }, []); + const onSave = () => { + const wallStore = useWallStore.getState(); + const selectedNode = wallStore.selectedNode; + const _editValue = wallStore.editValue; + if (selectedNode && _editValue) { + selectedNode.data.html = _editValue; + const newNodes = storeApi.getState().nodes.map((node) => (node.id === selectedNode.id ? selectedNode : node)); + storeApi.setState({ nodes: newNodes }); + if (wallStore.id) { + message.success('保存成功', { + closeOnClick: true, + }); + } + wallStore.saveNodes(newNodes); + } + }; + let html = selectedNode?.data?.html || ''; + if (html === BlankNoteText) { + html = ''; + } + return ( +
+
+ + {selectedNode && ( +
+ +
+ )} +
+
+ {selectedNode && open && } +
+
+ ); +}; + +export default Drawer; diff --git a/src/pages/wall/modules/FormDialog.tsx b/src/pages/wall/modules/FormDialog.tsx new file mode 100644 index 0000000..6a5c6e9 --- /dev/null +++ b/src/pages/wall/modules/FormDialog.tsx @@ -0,0 +1,132 @@ +import React, { useState } from 'react'; +import { Dialog, DialogTitle, DialogContent, TextField, DialogActions, Button, Chip } from '@mui/material'; +import { useShallow } from 'zustand/react/shallow'; +import { getNodeData, useWallStore } from '../store/wall'; +import { useReactFlow, useStore } from '@xyflow/react'; +import { useUserWallStore } from '../store/user-wall'; +import { message } from '@/modules/message'; +import { useNavigate } from 'react-router-dom'; + +function FormDialog({ open, handleClose, handleSubmit, initialData }) { + const [data, setData] = useState(initialData || { title: '', description: '', summary: '', tags: [] }); + + const handleChange = (event) => { + setData({ ...data, [event.target.name]: event.target.value }); + }; + + const handleTagDelete = (tagToDelete) => { + setData({ ...data, tags: data.tags.filter((tag) => tag !== tagToDelete) }); + }; + + const handleAddTag = (event) => { + if (event.key === 'Enter' && event.target.value !== '') { + setData({ ...data, tags: [...data.tags, event.target.value] }); + event.target.value = ''; // Clear input after adding tag + } + }; + + return ( + + {initialData ? 'Edit Data' : 'Create Data'} + + + + + + {data.tags.map((tag, index) => ( + handleTagDelete(tag)} style={{ margin: '5px' }} /> + ))} + + + + + + + ); +} + +export default FormDialog; + +export const SaveModal = () => { + const wallStore = useWallStore(useShallow((state) => state)); + const userWallStore = useUserWallStore(useShallow((state) => state)); + const { showFormDialog, setShowFormDialog, formDialogData, setFormDialogData } = wallStore; + const reactFlowInstance = useReactFlow(); + const navigate = useNavigate(); + const { id } = wallStore; + const onSubmit = async (values) => { + const nodes = reactFlowInstance.getNodes(); + const data = { + nodes: getNodeData(nodes), + }; + const fromData = { + title: values.title, + description: values.description, + summary: values.summary, + tags: values.tags, + markType: 'wall' as 'wall', + data, + }; + const res = await userWallStore.saveWall(fromData, { refresh: true }); + if (res.code === 200) { + setShowFormDialog(false); + if (!id) { + // 新创建 + const data = res.data; + wallStore.clear(); + setTimeout(() => { + navigate(`/wall/${data.id}`); + }, 2000); + } else { + // 编辑 + wallStore.setData(res.data); + } + } else { + message.error('保存失败'); + } + }; + if (!showFormDialog) { + return null; + } + return setShowFormDialog(false)} handleSubmit={onSubmit} initialData={formDialogData} />; +}; diff --git a/src/pages/wall/modules/toolbar/Toolbar.tsx b/src/pages/wall/modules/toolbar/Toolbar.tsx new file mode 100644 index 0000000..c2939b7 --- /dev/null +++ b/src/pages/wall/modules/toolbar/Toolbar.tsx @@ -0,0 +1,272 @@ +import { PanelTopOpen, PanelTopClose, Save, Download, Upload, User, Trash, Plus } from 'lucide-react'; +import { useEffect, useState } from 'react'; +import { useShallow } from 'zustand/react/shallow'; +import { useWallStore } from '../../store/wall'; +import clsx from 'clsx'; +import { useUserWallStore } from '../../store/user-wall'; +import { redirectToLogin } from '@/modules/require-to-login'; +import { useStore } from '@xyflow/react'; +import { message } from '@/modules/message'; +import { useNavigate } from 'react-router-dom'; +import { ClickAwayListener } from '@mui/material'; +export const ToolbarItem = ({ + children, + showBorder = true, + onClick, + className, +}: { + children: React.ReactNode; + showBorder?: boolean; + onClick?: () => any; + className?: string; +}) => { + return ( +
+ {children} +
+ ); +}; +// 空白处点击,当不包函toolbar时候,关闭toolbar +export const useBlankClick = () => { + const { setToolbarOpen } = useWallStore( + useShallow((state) => { + return { + setToolbarOpen: state.setToolbarOpen, + }; + }), + ); + useEffect(() => { + const handleClick = (e: MouseEvent) => { + // 点击的内容,closest('.toolbar') + const target = e.target as HTMLElement; + const toolbar = target.closest('.toolbar'); // 往上找,找到toolbar为止 + console.log('toolbar', target, toolbar); + // if (!toolbar) { + // setToolbarOpen(false); + // } + }; + console.log('add event'); + document.addEventListener('click', handleClick); + return () => { + document.removeEventListener('click', handleClick); + }; + }, []); +}; +export const ToolbarContent = ({ open }) => { + if (!open) { + return null; + } + const wallStore = useWallStore(useShallow((state) => state)); + const userWallStore = useUserWallStore(useShallow((state) => state)); + const store = useStore((state) => state); + const hasLogin = !!userWallStore.user; + const navigate = useNavigate(); + type MenuItem = { + label: string; + key: string; + icon?: React.ReactNode; + children?: React.ReactNode; + className?: string; + onClick: () => any; + }; + const menuList: MenuItem[] = [ + { + label: '导出', + key: 'export', + icon: , + onClick: () => { + wallStore.exportWall(store.nodes); + }, + }, + { + label: '导入', + key: 'import', + icon: , + children: ( + <> +
+ +
+
导入
+ { + const file = e.target.files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onload = (e) => { + const data = e.target?.result; + const json = JSON.parse(data as string); + const keys = ['id', 'type', 'position', 'data']; + if (Array.isArray(json) && json.every((item) => keys.every((key) => item[key]))) { + const nodes = store.nodes; + const newNodes = json.filter((item) => { + return !nodes.find((node) => node.id === item.id); + }); + const _nodes = [...nodes, ...newNodes]; + store.setNodes(_nodes); + wallStore.saveNodes(_nodes); + } else { + message.error('文件格式错误'); + } + }; + reader.readAsText(file); + } + }} + /> + + ), + onClick: () => { + const input = document.querySelector('#import-file')! as HTMLInputElement; + if (input) { + input.click(); + } else { + message.error('请选择文件'); + } + }, + }, + { + label: '清空', + key: 'clear', + icon: , + onClick: async () => { + await wallStore.clear(); + message.success('清空成功'); + store.setNodes([]); + }, + }, + ]; + + if (!hasLogin) { + menuList.push({ + label: '登录', + key: 'login', + icon: , + onClick: () => { + redirectToLogin(); + }, + }); + if (wallStore.id) { + menuList.push({ + label: '删除', + key: 'delete', + icon: , + onClick: async () => { + const res = await userWallStore.deleteWall(wallStore.id!); + if (res.code === 200) { + navigate('/'); + } + }, + }); + } + } else { + if (!wallStore.id) { + menuList.push({ + label: '保存到账号', + key: 'saveToAccount', + icon: , + onClick: () => { + wallStore.setShowFormDialog(true); + wallStore.setFormDialogData({ + title: '', + description: '', + tags: [], + summary: '', + }); + }, + }); + } else { + menuList.push({ + label: '编辑信息', + key: 'saveToAccount', + icon: , + onClick: () => { + wallStore.setShowFormDialog(true); + const data = wallStore.data; + wallStore.setFormDialogData({ + title: data?.title, + description: data?.description, + tags: data?.tags, + summary: data?.summary, + }); + }, + }); + menuList.push({ + label: '新增', + key: 'add', + icon: , + onClick: () => { + navigate(`/`); + wallStore.clearQueryWall(); + }, + }); + menuList.push({ + label: '删除', + key: 'delete', + icon: , + className: 'text-red-500', + onClick: async () => { + const res = await userWallStore.deleteWall(wallStore.id!); + if (res.code === 200) { + message.success('删除成功,返回首页'); + wallStore.clearQueryWall(); + navigate('/'); + } + }, + }); + } + menuList.push({ + label: '退出 ', + key: 'logout', + icon: , + onClick: () => { + userWallStore.logout(); + }, + }); + } + return ( + wallStore.setToolbarOpen(false)}> +
+ {menuList.map((item) => ( + { + item.onClick?.(); + if (item.key !== 'import') { + wallStore.setToolbarOpen(false); + } + }}> + {item.children ? ( + <>{item.children} + ) : ( + <> +
{item.icon}
+
{item.label}
+ + )} +
+ ))} +
{wallStore.id ? 'id:' + wallStore.id : '临时编辑,资源缓存在本地'}
+ {hasLogin &&
用户: {userWallStore.user?.username}
} +
+
+ ); +}; +export const Toolbar = () => { + const wallStore = useWallStore(useShallow((state) => state)); + const { toolbarOpen, setToolbarOpen } = wallStore; + + return ( +
+
setToolbarOpen(!toolbarOpen)}> + + +
+ +
+ ); +}; diff --git a/src/pages/wall/pages/List.tsx b/src/pages/wall/pages/List.tsx new file mode 100644 index 0000000..b4b921f --- /dev/null +++ b/src/pages/wall/pages/List.tsx @@ -0,0 +1,64 @@ +import { useEffect } from 'react'; +import { useWallStore } from '../store/wall'; +import { useUserWallStore } from '../store/user-wall'; +import { useShallow } from 'zustand/react/shallow'; +import { formatDate, formatRelativeDate } from '../../../modules/dayjs'; +import { useNavigate } from 'react-router-dom'; +export const List = () => { + const navigate = useNavigate(); + const wallStore = useUserWallStore( + useShallow((state) => { + return { + wallList: state.wallList, + queryWallList: state.queryWallList, + }; + }), + ); + useEffect(() => { + init(); + }, []); + const init = () => { + wallStore.queryWallList(); + }; + return ( +
+
+
Wall Note
+
+
+
+ {wallStore.wallList.map((wall) => { + return ( +
{ + navigate(`/wall/${wall.id}`); + }}> +
+
{wall.title}
+
+
+
{wall.summary}
+
+ {wall?.tags?.map?.((tag) => { + return ( +
+ {tag} +
+ ); + })} +
+
+
+
{formatDate(wall?.createdAt, 'YYYY-MM-DD')}
+
{formatRelativeDate(wall?.createdAt)}
+
+
+ ); + })} +
+
+
+ ); +}; diff --git a/src/pages/wall/store/user-wall.ts b/src/pages/wall/store/user-wall.ts new file mode 100644 index 0000000..fe6fc0f --- /dev/null +++ b/src/pages/wall/store/user-wall.ts @@ -0,0 +1,104 @@ +import { message } from '@/modules/message'; +import { query } from '@/modules/query'; +import { create } from 'zustand'; +type User = { + id: string; + username: string; + avatar: string; +}; +type Wall = { + id?: string; + title?: string; + description?: string; + type?: 'wall'; + data?: { + [key: string]: any; + }; + link?: string; + summary?: string; + tags?: string[]; + createdAt?: string; + updatedAt?: string; + uid?: string; + [key: string]: any; +}; + +interface UserWallStore { + user?: User; + setUser: (user: User) => void; + queryMe: (openOnNoLogin?: boolean) => Promise; + wallList: Wall[]; + queryWallList: () => Promise; + logout: () => void; + saveWall: (data: Wall, opts?: { refresh?: boolean, showMessage?: boolean }) => Promise; + queryWall: (id: string) => Promise; + deleteWall: (id: string) => Promise; +} + +export const useUserWallStore = create((set, get) => ({ + user: undefined, + setUser: (user: User) => set({ user }), + queryMe: async (openOnNoLogin = true) => { + const res = await query.post( + { + path: 'user', + key: 'me', + }, + { + afterResponse: !openOnNoLogin ? async (res) => res : undefined, + }, + ); + console.log('queryMe', res); + if (res.code === 200) { + set({ user: res.data }); + } + }, + wallList: [], + queryWallList: async () => { + const res = await query.post({ + path: 'mark', + key: 'list', + markType: 'wall', + page: 1, + pageSize: 10, + }); + if (res.code === 200) { + set({ wallList: res.data.list }); + } + }, + saveWall: async (data: Wall, opts?: { refresh?: boolean, showMessage?: boolean }) => { + const { queryWallList } = get(); + const res = await query.post({ + path: 'mark', + key: 'update', + data, + }); + if (res.code === 200) { + // 刷新列表 + opts?.refresh && (await queryWallList()); + opts?.showMessage && message.success('保存成功'); + return res; + } + return res; + }, + queryWall: async (id: string) => { + const res = await query.post({ + path: 'mark', + key: 'get', + id, + }); + return res; + }, + deleteWall: async (id: string) => { + const res = await query.post({ + path: 'mark', + key: 'delete', + id, + }); + return res; + }, + logout: () => { + set({ user: undefined }); + localStorage.removeItem('token'); + }, +})); diff --git a/src/pages/wall/store/wall.ts b/src/pages/wall/store/wall.ts new file mode 100644 index 0000000..f5e7623 --- /dev/null +++ b/src/pages/wall/store/wall.ts @@ -0,0 +1,162 @@ +import { create } from 'zustand'; +import { XYPosition } from '@xyflow/react'; +import { getWallData, setWallData } from '../utils/db'; +import { useUserWallStore } from './user-wall'; +import { redirectToLogin } from '@/modules/require-to-login'; +import { message } from '@/modules/message'; + +type NodeData = { + id: string; + position: XYPosition; + data: T; + type?: string; // wall +}; +export const getNodeData = (nodes: NodeData[]) => { + return nodes.map((node) => ({ + id: node.id, + position: node.position, + data: node.data, + type: node.type, + })); +}; + +interface WallState { + // 只做传递 + nodes: NodeData[]; + setNodes: (nodes: NodeData[]) => void; + saveNodes: (nodes: NodeData[]) => Promise; + open: boolean; + setOpen: (open: boolean) => void; + selectedNode: NodeData | null; + setSelectedNode: (node: NodeData | null) => void; + editValue: string; + setEditValue: (value: string) => void; + data?: any; + setData: (data: any) => void; + init: (id?: string | null) => Promise; + id: string | null; + setId: (id: string | null) => void; + loading: boolean; + setLoading: (loading: boolean) => void; + loaded: boolean | 'error'; + toolbarOpen: boolean; + setToolbarOpen: (open: boolean) => void; + showFormDialog: boolean; + setShowFormDialog: (show: boolean) => void; + formDialogData: any; + setFormDialogData: (data: any) => void; + clear: () => Promise; + exportWall: (nodes: NodeData[]) => Promise; + clearQueryWall: () => Promise; +} +const initialNodes = [ + // { id: '1', type: 'wall', position: { x: 0, y: 0 }, data: { html: '1' } }, + { + id: '1', + type: 'wall', + position: { x: 0, y: 0 }, + data: { html: 'sadfsdaf1 sadfsdaf1 sadfsdaf1 sadfsdaf1 sadfsdaf1 sadfsdaf1 sadfsdaf1 sadfsdaf1', width: 410, height: 212 }, + }, + // { id: '2', type: 'wall', position: { x: 0, y: 100 }, data: { html: '3332' } }, +]; + +export const useWallStore = create((set, get) => ({ + nodes: [], + loading: false, + setLoading: (loading) => set({ loading }), + setNodes: (nodes) => { + set({ nodes }); + }, + saveNodes: async (nodes: NodeData[]) => { + if (!get().id) { + const covertData = getNodeData(nodes); + setWallData({ nodes: covertData }); + } else { + const { id } = get(); + const userWallStore = useUserWallStore.getState(); + console.log('saveNodes id', id); + if (id) { + const covertData = getNodeData(nodes); + const res = await userWallStore.saveWall({ + id, + data: { + nodes: covertData, + }, + }); + if (res.code === 200) { + // console.log('saveNodes res', res); + message.success('保存成功', { + closeOnClick: true, + }); + } + } + } + }, + open: false, + setOpen: (open) => set({ open }), + selectedNode: null, + setSelectedNode: (node) => set({ selectedNode: node }), + editValue: '', + setEditValue: (value) => set({ editValue: value }), + data: null, + setData: (data) => set({ data }), + id: null, + setId: (id) => set({ id }), + loaded: false, + init: async (id?: string | null) => { + // 如果登陆了且如果有id,从服务器获取 + // 没有id,获取缓存 + const hasLogin = localStorage.getItem('token'); + if (hasLogin && id) { + const res = await useUserWallStore.getState().queryWall(id); + if (res.code === 200) { + set({ nodes: res.data?.data?.nodes || [], loaded: true, id, data: res.data }); + } else { + // message.error('获取失败,请稍后刷新重试'); + set({ loaded: 'error' }); + } + } else if (!hasLogin && id) { + // 没有登陆,但是有id,从服务器获取 + // 跳转到登陆页面 + redirectToLogin(); + } else { + const data = await getWallData(); + set({ nodes: data?.nodes || [], loaded: true }); + } + }, + toolbarOpen: false, + setToolbarOpen: (open) => set({ toolbarOpen: open }), + showFormDialog: false, + setShowFormDialog: (show) => set({ showFormDialog: show }), + formDialogData: null, + setFormDialogData: (data) => set({ formDialogData: data }), + clear: async () => { + if (get().id) { + set({ nodes: initialNodes, id: null, selectedNode: null, editValue: '', data: null }); + await useUserWallStore.getState().saveWall({ + id: get().id!, + data: { + nodes: [], + }, + }); + } else { + set({ nodes: initialNodes, id: null, selectedNode: null, editValue: '', data: null }); + await setWallData({ nodes: [] }); + } + }, + exportWall: async (nodes: NodeData[]) => { + const covertData = getNodeData(nodes); + setWallData({ nodes: covertData }); + // 导出为json + const json = JSON.stringify(covertData); + const blob = new Blob([json], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'wall.json'; + a.click(); + }, + clearQueryWall: async () => { + set({ nodes: initialNodes, id: null, selectedNode: null, editValue: '', data: null, toolbarOpen: false, loaded: false }); + }, +})); diff --git a/src/pages/wall/utils/convet.ts b/src/pages/wall/utils/convet.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/wall/utils/db.ts b/src/pages/wall/utils/db.ts new file mode 100644 index 0000000..2da8dda --- /dev/null +++ b/src/pages/wall/utils/db.ts @@ -0,0 +1,14 @@ +import { get, set, clear } from 'idb-keyval'; + +export async function getWallData() { + const data = await get('cacheWall'); + return data; +} + +export async function setWallData(data: any) { + await set('cacheWall', data); +} + +export async function clearWallData() { + await clear(); +} diff --git a/src/pages/wall/utils/is-mac.ts b/src/pages/wall/utils/is-mac.ts new file mode 100644 index 0000000..b3b5d3e --- /dev/null +++ b/src/pages/wall/utils/is-mac.ts @@ -0,0 +1,11 @@ +export const isMac = async () => { + // Check if the newer API is available + const navigator = window.navigator as Navigator & { userAgentData: { getHighEntropyValues: (keys: string[]) => Promise<{ platform: string }> } }; + if (navigator.userAgentData) { + const uaData = await navigator.userAgentData.getHighEntropyValues(['platform']); + return uaData.platform === 'macOS'; + } else { + // Fallback to using the older userAgent string + return /Macintosh|Mac OS X/i.test(navigator.userAgent); + } +}; diff --git a/src/pages/wall/utils/random.ts b/src/pages/wall/utils/random.ts new file mode 100644 index 0000000..a985de6 --- /dev/null +++ b/src/pages/wall/utils/random.ts @@ -0,0 +1,10 @@ +import { customAlphabet } from 'nanoid'; +const alphabet = '0123456789abcdefghijklmnopqrstuvwxyz'; +const alphabetLetters = 'abcdefghijklmnopqrstuvwxyz'; +export const randomString = customAlphabet(alphabet, 10); +export const randomLetters = customAlphabet(alphabetLetters, 10); +export const randomId = () => { + const firstChar = randomLetters(1); + const restChars = randomString(21); + return firstChar + restChars; +}; diff --git a/vite.config.ts b/vite.config.ts index a2b5562..0fabd28 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'vite'; +import { defineConfig, ProxyOptions } from 'vite'; import react from '@vitejs/plugin-react'; import path from 'path'; import tailwindcss from '@tailwindcss/vite'; @@ -9,12 +9,35 @@ const version = pkgs.version || '0.0.1'; const isDev = process.env.NODE_ENV === 'development'; -const basename = isDev ? '/' : '/username/app'; +const basename = isDev ? '/' : '/apps/wallnote'; const plugins = [] const isWeb = false; +const isKevisual = true; + if(isWeb) { plugins.push(basicSsl()) } +let proxy:Record = { +} +if(isKevisual) { + proxy = { + '/api': { + target: 'https://kevisual.xiongxiao.me', + changeOrigin: true, + }, + '/api/router': { + target: 'ws://localhost:3000', + changeOrigin: true, + ws: true, + rewriteWsOrigin: true, + rewrite: (path) => path.replace(/^\/api/, '/api'), + }, + '/root/center': { + target: 'https://kevisual.xiongxiao.me', + changeOrigin: true, + }, + } +} // https://vitejs.dev/config/ export default defineConfig({ plugins: [react(), tailwindcss(), ...plugins], @@ -48,6 +71,7 @@ export default defineConfig({ rewriteWsOrigin: true, rewrite: (path) => path.replace(/^\/api/, '/api'), }, + ...proxy, }, }, });