From 27f487c48fba884ad4254c75d0b28398e281127b Mon Sep 17 00:00:00 2001 From: xion Date: Mon, 23 Sep 2024 20:51:59 +0800 Subject: [PATCH] feat: add listen code change --- index.html | 2 +- package.json | 8 +- pnpm-lock.yaml | 141 +++++++++--------- src/App.tsx | 2 + src/modules/index.ts | 29 +++- .../code-editor/hooks/use-to-code-editor.ts | 29 ++++ src/pages/code-editor/index.tsx | 75 ++++++++++ src/pages/code-editor/store.ts | 84 +++++++++++ src/pages/container/preview/index.tsx | 85 ++++++++++- src/pages/panel/deck/index.tsx | 19 ++- src/pages/panel/edit/List.tsx | 9 +- src/utils/history.ts | 22 +++ vite.config.ts | 11 +- 13 files changed, 419 insertions(+), 97 deletions(-) create mode 100644 src/pages/code-editor/hooks/use-to-code-editor.ts create mode 100644 src/pages/code-editor/index.tsx create mode 100644 src/pages/code-editor/store.ts create mode 100644 src/utils/history.ts diff --git a/index.html b/index.html index e4b78ea..0bcc9f9 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - Vite + React + TS + envision
diff --git a/package.json b/package.json index ac0376a..7ff2c32 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "vite-react", + "name": "@kevisual/envision", "private": true, "version": "0.0.0", "type": "module", @@ -12,17 +12,17 @@ "deploy": "rsync -avz --delete ./dist/ light:/root/apps/envision/web" }, "dependencies": { - "@abearxiong/container": "0.0.1-alpha.4", + "@abearxiong/container": "0.0.1-alpha.6", "@abearxiong/flows": "0.0.1-alpha.9", "@abearxiong/ui": "0.0.1-alpha.0", "@ant-design/icons": "^5.5.1", "@icon-park/react": "^1.4.2", - "@kevisual/codemirror": "^0.0.1", + "@kevisual/codemirror": "^0.0.2", "@kevisual/query": "^0.0.2", "@kevisual/ui": "^0.0.2", "@uiw/react-textarea-code-editor": "^3.0.2", "@xyflow/react": "^12.3.0", - "antd": "^5.20.6", + "antd": "^5.21.0", "classnames": "^2.5.1", "clsx": "^2.1.1", "copy-to-clipboard": "^3.3.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf7954d..0030ac8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@abearxiong/container': - specifier: 0.0.1-alpha.4 - version: 0.0.1-alpha.4(@emotion/css@11.13.0)(crypto-js@4.2.0)(eventemitter3@5.0.1) + specifier: 0.0.1-alpha.6 + version: 0.0.1-alpha.6(@emotion/css@11.13.0)(crypto-js@4.2.0)(eventemitter3@5.0.1) '@abearxiong/flows': specifier: 0.0.1-alpha.9 version: 0.0.1-alpha.9(@xyflow/react@12.3.0(@types/react@18.3.8)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(zustand@4.5.5(@types/react@18.3.8)(immer@10.1.1)(react@18.3.1)) @@ -24,8 +24,8 @@ importers: specifier: ^1.4.2 version: 1.4.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@kevisual/codemirror': - specifier: ^0.0.1 - version: 0.0.1 + specifier: ^0.0.2 + version: 0.0.2 '@kevisual/query': specifier: ^0.0.2 version: 0.0.2 @@ -39,8 +39,8 @@ importers: specifier: ^12.3.0 version: 12.3.0(@types/react@18.3.8)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) antd: - specifier: ^5.20.6 - version: 5.20.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^5.21.0 + version: 5.21.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) classnames: specifier: ^2.5.1 version: 2.5.1 @@ -141,8 +141,8 @@ importers: packages: - '@abearxiong/container@0.0.1-alpha.4': - resolution: {integrity: sha512-92qU430DQu5p+m6UhlQHyC3LWi/hbrGrDh0pTvhA181ePT/3EwXz3nnHdsHYU+Di2c5qMQEBH1TCMmZaoeacJg==, tarball: https://npm.pkg.github.com/download/@abearxiong/container/0.0.1-alpha.4/c35c637deeda7c86944047f2d39316e03bd2405c} + '@abearxiong/container@0.0.1-alpha.6': + resolution: {integrity: sha512-rhEPkVWGOxn8o7kVSgkHOpc+/PybOQTYt/V9BQpVzM6nXw5Sl1fDCaQux2Nn06bz54bU1O38wGfk6y46S0weSw==, tarball: https://npm.pkg.github.com/download/@abearxiong/container/0.0.1-alpha.6/77e190e08005b8eb0f2a5ca5a6778ae727bdc263} peerDependencies: '@emotion/css': ^11.13.0 crypto-js: ^4.2.0 @@ -546,8 +546,8 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@kevisual/codemirror@0.0.1': - resolution: {integrity: sha512-uW1pm4Q9+WNCeCgKgpHzx01kumFiMMjsor3rF8iyiEmcWNnHnGwj1eLtPs4Ux1ID0Mh2sn3OMKFvUZjcNFi/wA==} + '@kevisual/codemirror@0.0.2': + resolution: {integrity: sha512-z+hINypSarYBj+13en8+Hj/CqTAMVIYN3Rs0ICHRzbikvrDnsnT4ohpnFgcbFPQ/zX3E1mS9ANbx4jGSJEHaPQ==} '@kevisual/query@0.0.2': resolution: {integrity: sha512-xE2KhqlF2WDJ8Mt/AKKYnKeBPGxlbNhh7uXSxhO1/Rz95SVfJm0QF6pCEiWi/OHQ93gxIt5qUNEGp9avXHsWxw==} @@ -910,11 +910,8 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} - antd@5.20.6: - resolution: {integrity: sha512-TZFmNenHlh26DelHCJbkB+x1OVulIKsN1f/CnAd2NxZLysXqRvSuLUeHcgccqAnxTy7B03GZ6i1tocGxPCNjgA==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' + antd@5.21.0: + resolution: {integrity: sha512-eoY3LruXq/8MRCXG46O2cwc+Q8HW8Bhc+pWw7loIt6Dn22tLHckxYF/663kn55JTIOVUnJdmJDP9njdJmLXJsQ==} any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -1733,14 +1730,14 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - rc-collapse@3.7.3: - resolution: {integrity: sha512-60FJcdTRn0X5sELF18TANwtVi7FtModq649H11mYF1jh83DniMoM4MqY627sEKRCTm4+WXfGDcB7hY5oW6xhyw==} + rc-collapse@3.8.0: + resolution: {integrity: sha512-YVBkssrKPBG09TGfcWWGj8zJBYD9G3XuTy89t5iUmSXrIXEAnO1M+qjUxRW6b4Qi0+wNWG6MHJF/+US+nmIlzA==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' - rc-dialog@9.5.2: - resolution: {integrity: sha512-qVUjc8JukG+j/pNaHVSRa2GO2/KbV2thm7yO4hepQ902eGdYK913sGkwg/fh9yhKYV1ql3BKIN2xnud3rEXAPw==} + rc-dialog@9.6.0: + resolution: {integrity: sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -1764,8 +1761,8 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - rc-image@7.9.0: - resolution: {integrity: sha512-l4zqO5E0quuLMCtdKfBgj4Suv8tIS011F5k1zBBlK25iMjjiNHxA0VeTzGFtUZERSA45gvpXDg8/P6qNLjR25g==} + rc-image@7.11.0: + resolution: {integrity: sha512-aZkTEZXqeqfPZtnSdNUnKQA0N/3MbgR7nUnZ+/4MfSFWPFHZau4p5r5ShaI0KPEMnNjv4kijSCFq/9wtJpwykw==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -1782,14 +1779,14 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' - rc-mentions@2.15.0: - resolution: {integrity: sha512-f5v5i7VdqvBDXbphoqcQWmXDif2Msd2arritVoWybrVDuHE6nQ7XCYsybHbV//WylooK52BFDouFvyaRDtXZEw==} + rc-mentions@2.16.1: + resolution: {integrity: sha512-GnhSTGP9Mtv6pqFFGQze44LlrtWOjHNrUUAcsdo9DnNAhN4pwVPEWy4z+2jpjkiGlJ3VoXdvMHcNDQdfI9fEaw==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' - rc-menu@9.14.1: - resolution: {integrity: sha512-5wlRb3M8S4yGlWhSoEYJ7ZVRElyScdcpUHxgiLxkeig1tEdyKrnED3B2fhpN0Rrpdp9jyhnmZR/Lwq2fH5VvDQ==} + rc-menu@9.15.1: + resolution: {integrity: sha512-UKporqU6LPfHnpPmtP6hdEK4iO5Q+b7BRv/uRpxdIyDGplZy9jwUjsnpev5bs3PQKB0H0n34WAPDfjAfn3kAPA==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -1813,8 +1810,8 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - rc-pagination@4.2.0: - resolution: {integrity: sha512-V6qeANJsT6tmOcZ4XiUmj8JXjRLbkusuufpuoBw2GiAn94fIixYjFLmbruD1Sbhn8fPLDnWawPp4CN37zQorvw==} + rc-pagination@4.3.0: + resolution: {integrity: sha512-UubEWA0ShnroQ1tDa291Fzw6kj0iOeF26IsUObxYTpimgj4/qPCWVFl18RLZE+0Up1IZg0IK4pMn6nB3mjvB7g==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -1858,8 +1855,8 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - rc-segmented@2.3.0: - resolution: {integrity: sha512-I3FtM5Smua/ESXutFfb8gJ8ZPcvFR+qUgeeGFQHBOvRiRKyAk4aBE5nfqrxXx+h8/vn60DQjOt6i4RNtrbOobg==} + rc-segmented@2.5.0: + resolution: {integrity: sha512-B28Fe3J9iUFOhFJET3RoXAPFJ2u47QvLSYcZWC4tFYNGPEjug5LAxEasZlA/PpAxhdOPqGWsGbSj7ftneukJnw==} peerDependencies: react: '>=16.0.0' react-dom: '>=16.0.0' @@ -1891,28 +1888,28 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - rc-table@7.45.7: - resolution: {integrity: sha512-wi9LetBL1t1csxyGkMB2p3mCiMt+NDexMlPbXHvQFmBBAsMxrgNSAPwUci2zDLUq9m8QdWc1Nh8suvrpy9mXrg==} + rc-table@7.47.5: + resolution: {integrity: sha512-fzq+V9j/atbPIcvs3emuclaEoXulwQpIiJA6/7ey52j8+9cJ4P8DGmp4YzfUVDrb3qhgedcVeD6eRgUrokwVEQ==} engines: {node: '>=8.x'} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' - rc-tabs@15.1.1: - resolution: {integrity: sha512-Tc7bJvpEdkWIVCUL7yQrMNBJY3j44NcyWS48jF/UKMXuUlzaXK+Z/pEL5LjGcTadtPvVmNqA40yv7hmr+tCOAw==} + rc-tabs@15.2.0: + resolution: {integrity: sha512-ZfHdGw0krK4walBYNOgPWCcBImSp5NtzJR5+oI4rN9Z44FYDQKozBFfuAQHhumIUtx4EmGaYCFjywwgca/Rs1g==} engines: {node: '>=8.x'} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' - rc-textarea@1.8.1: - resolution: {integrity: sha512-bm36N2ZqwZAP60ZQg2OY9mPdqWC+m6UTjHc+CqEZOxb3Ia29BGHazY/s5bI8M4113CkqTzhtFUDNA078ZiOx3Q==} + rc-textarea@1.8.2: + resolution: {integrity: sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' - rc-tooltip@6.2.0: - resolution: {integrity: sha512-iS/3iOAvtDh9GIx1ulY7EFUXUtktFccNLsARo3NPgLf0QW9oT0w3dA9cYWlhqAKmD+uriEwdWz1kH0Qs4zk2Aw==} + rc-tooltip@6.2.1: + resolution: {integrity: sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -1930,8 +1927,8 @@ packages: react: '*' react-dom: '*' - rc-upload@4.7.0: - resolution: {integrity: sha512-eUwxYNHlsYe5vYhKFAUGrQG95JrnPzY+BmPi1Daq39fWNl/eOc7v4UODuWrVp2LFkQBuV3cMCG/I68iub6oBrg==} + rc-upload@4.8.1: + resolution: {integrity: sha512-toEAhwl4hjLAI1u8/CgKWt30BR06ulPa4iGQSMvSXoHzO88gPCslxqV/mnn4gJU7PDoltGIC9Eh+wkeudqgHyw==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -2373,7 +2370,7 @@ packages: snapshots: - '@abearxiong/container@0.0.1-alpha.4(@emotion/css@11.13.0)(crypto-js@4.2.0)(eventemitter3@5.0.1)': + '@abearxiong/container@0.0.1-alpha.6(@emotion/css@11.13.0)(crypto-js@4.2.0)(eventemitter3@5.0.1)': dependencies: '@emotion/css': 11.13.0 crypto-js: 4.2.0 @@ -2792,7 +2789,7 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 - '@kevisual/codemirror@0.0.1': {} + '@kevisual/codemirror@0.0.2': {} '@kevisual/query@0.0.2': {} @@ -3177,7 +3174,7 @@ snapshots: ansi-styles@6.2.1: {} - antd@5.20.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + antd@5.21.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@ant-design/colors': 7.1.0 '@ant-design/cssinjs': 1.21.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -3196,44 +3193,44 @@ snapshots: dayjs: 1.11.13 rc-cascader: 3.28.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-checkbox: 3.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-collapse: 3.7.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-dialog: 9.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-collapse: 3.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-dialog: 9.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-drawer: 7.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-dropdown: 4.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-field-form: 2.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-image: 7.9.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-image: 7.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-input: 1.6.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-input-number: 9.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-mentions: 2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-menu: 9.14.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-mentions: 2.16.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-menu: 9.15.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-motion: 2.9.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-notification: 5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-pagination: 4.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-pagination: 4.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-picker: 4.6.14(dayjs@1.11.13)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-progress: 4.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-rate: 2.13.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-resize-observer: 1.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-segmented: 2.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-segmented: 2.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-select: 14.15.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-slider: 11.1.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-steps: 6.0.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-switch: 4.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-table: 7.45.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-tabs: 15.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-textarea: 1.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-tooltip: 6.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-table: 7.47.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-tabs: 15.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-textarea: 1.8.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-tooltip: 6.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-tree: 5.9.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-tree-select: 5.23.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-upload: 4.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-upload: 4.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-util: 5.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) scroll-into-view-if-needed: 3.1.0 throttle-debounce: 5.0.2 transitivePeerDependencies: - date-fns - luxon - moment + - react + - react-dom any-promise@1.3.0: {} @@ -4060,7 +4057,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-collapse@3.7.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-collapse@3.8.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 classnames: 2.5.1 @@ -4069,7 +4066,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-dialog@9.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-dialog@9.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 '@rc-component/portal': 1.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -4106,12 +4103,12 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-image@7.9.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-image@7.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 '@rc-component/portal': 1.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) classnames: 2.5.1 - rc-dialog: 9.5.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-dialog: 9.6.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-motion: 2.9.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-util: 5.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 @@ -4135,19 +4132,19 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-mentions@2.15.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-mentions@2.16.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 '@rc-component/trigger': 2.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) classnames: 2.5.1 rc-input: 1.6.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-menu: 9.14.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-textarea: 1.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-menu: 9.15.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-textarea: 1.8.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-util: 5.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-menu@9.14.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-menu@9.15.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 '@rc-component/trigger': 2.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -4184,7 +4181,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-pagination@4.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-pagination@4.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 classnames: 2.5.1 @@ -4230,7 +4227,7 @@ snapshots: react-dom: 18.3.1(react@18.3.1) resize-observer-polyfill: 1.5.1 - rc-segmented@2.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-segmented@2.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 classnames: 2.5.1 @@ -4275,7 +4272,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-table@7.45.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-table@7.47.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 '@rc-component/context': 1.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -4286,19 +4283,19 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-tabs@15.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-tabs@15.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 classnames: 2.5.1 rc-dropdown: 4.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - rc-menu: 9.14.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + rc-menu: 9.15.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-motion: 2.9.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-resize-observer: 1.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) rc-util: 5.43.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-textarea@1.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-textarea@1.8.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 classnames: 2.5.1 @@ -4308,7 +4305,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-tooltip@6.2.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-tooltip@6.2.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 '@rc-component/trigger': 2.2.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -4336,7 +4333,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - rc-upload@4.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + rc-upload@4.8.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.6 classnames: 2.5.1 diff --git a/src/App.tsx b/src/App.tsx index 7d84f1d..e895a7e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,6 +3,7 @@ import { ConfigProvider } from 'antd'; import { App as ContainerApp } from './pages/container'; import { App as PanelApp } from './pages/panel'; import { App as PublishApp } from './pages/publish'; +import { App as CodeEditorApp } from './pages/code-editor'; export const App = () => { return ( @@ -17,6 +18,7 @@ export const App = () => { } /> } /> } /> + } /> 404} /> 404} /> diff --git a/src/modules/index.ts b/src/modules/index.ts index 402bce6..e1e0783 100644 --- a/src/modules/index.ts +++ b/src/modules/index.ts @@ -1,5 +1,30 @@ import { Query } from '@kevisual/query'; - export const query = new Query({}); - export const request = query.post; +export const ws = new WebSocket('ws://localhost:6010/api/router'); +import { create } from 'zustand'; + +type Store = { + connected: boolean; + setConnected: (connected: boolean) => void; +}; +export const useStore = create((set) => ({ + connected: false, + setConnected: (connected) => set({ connected }), +})); + +// 当连接成功时 +ws.onopen = () => { + console.log('Connected to WebSocket server'); + useStore.getState().setConnected(true); +}; +// 接收服务器的消息 +ws.onmessage = (event) => { + console.log('Received message:', event.data); + // const message = JSON.parse(event.data); +}; + +// 处理 WebSocket 关闭 +ws.onclose = () => { + console.log('Disconnected from WebSocket server'); +}; diff --git a/src/pages/code-editor/hooks/use-to-code-editor.ts b/src/pages/code-editor/hooks/use-to-code-editor.ts new file mode 100644 index 0000000..060c53e --- /dev/null +++ b/src/pages/code-editor/hooks/use-to-code-editor.ts @@ -0,0 +1,29 @@ +import { useNavigate } from 'react-router'; +import { ParseData } from '../store'; +export const useToCodeEditor = () => { + const navigate = useNavigate(); + const toPage = (pathKey: ParseData['updatePath'], data: ParseData['data']) => { + navigate('/code-editor', { + state: { + updatePath: pathKey, + data, + }, + }); + }; + const PageUpdate = { + path: 'page', + key: 'update', + }; + const toPagePage = (data: ParseData['data']) => { + navigate('/code-editor', { + state: { + updatePath: PageUpdate, + data, + }, + }); + }; + return { + toPage, + toPagePage, + }; +}; diff --git a/src/pages/code-editor/index.tsx b/src/pages/code-editor/index.tsx new file mode 100644 index 0000000..86d71a1 --- /dev/null +++ b/src/pages/code-editor/index.tsx @@ -0,0 +1,75 @@ +import { createEditorInstance, editor } from '@kevisual/codemirror/dist/editor.json'; +import { useEffect, useRef, useLayoutEffect, useState, useCallback } from 'react'; +import { useLocation, useNavigate } from 'react-router'; +import { useCodeEditorStore, ParseData } from './store'; +import { useToCodeEditor } from './hooks/use-to-code-editor'; +export { useToCodeEditor }; +import { Button, message } from 'antd'; +export const App = () => { + const ref = useRef(null); + const editorRef = useRef(null); + const location = useLocation(); + const store = useCodeEditorStore(); + const [mounted, setMounted] = useState(false); + useEffect(() => { + initEditor(); + const state = location.state as ParseData; + if (state && state.data) { + store.init(state); + } + setMounted(true); + return () => { + setMounted(false); + }; + }, []); + useLayoutEffect(() => { + if (!mounted) return; + if (editorRef.current) { + setNewValue(store.code); + } else { + setNewValue(''); + } + }, [store.code, mounted]); + const initEditor = () => { + const _editor = createEditorInstance(ref.current!); + editorRef.current = _editor; + }; + const setNewValue = (value: string) => { + const editor = editorRef.current; + if (editor) { + editor.dispatch({ + changes: [{ from: 0, to: editor.state.doc.length, insert: value }], + }); + } + }; + const getValue = () => { + const editor = editorRef.current; + if (editor) { + return editor.state.doc.toString(); + } + return ''; + }; + const onSave = useCallback(async () => { + const value = getValue(); + // store.onUpdate(value); + if (store.dataType === 'object') { + try { + JSON.parse(value); + } catch (error) { + console.error(error); + message.error('JSON format error'); + return; + } + } + store.onUpdate(value); + }, [store.dataType]); + return ( +
+
Code Editor
+ +
+
+
+
+ ); +}; diff --git a/src/pages/code-editor/store.ts b/src/pages/code-editor/store.ts new file mode 100644 index 0000000..3cf4100 --- /dev/null +++ b/src/pages/code-editor/store.ts @@ -0,0 +1,84 @@ +import { create } from 'zustand'; +import { produce } from 'immer'; +import { query } from '@/modules'; + +type QueryPath = { + key?: string; + path?: string; +}; +export type ParseData = { + updatePath: QueryPath; + data?: string | Object; +}; +type CodeEditorStore = { + code: string; + type: string; // javascript, json + setCode: (code: string) => void; + loading: boolean; + setLoading: (loading: boolean) => void; + data: any; + dataType: string | Object; + setData: (data: any) => void; + updatePath: QueryPath; + setUpdatePath: (updatePath: any) => void; + onUpdate: (data: string) => Promise; + init: (parseData: { updatePath: QueryPath; data?: string | Object }) => void; +}; +export const useCodeEditorStore = create((set, get) => ({ + code: '', + type: 'javascript', + setCode: (code: string) => set({ code }), + loading: false, + setLoading: (loading: boolean) => set({ loading }), + data: {}, + dataType: 'json', + setData: (data: any) => set({ data }), + updatePath: {}, + setUpdatePath: (updatePath) => set({ updatePath }), + onUpdate: async (data: string) => { + const { updatePath, dataType } = get(); + const { path, key } = updatePath; + let _newData = data; + if (dataType === 'object') { + try { + _newData = JSON.parse(data); + } catch (error) { + console.error(error); + return; + } + } else if (dataType === 'string') { + _newData = data; + } + if (path && key) { + const res = await query.post({ path, key, data: _newData }); + if (res.code === 200) { + set( + produce((state) => { + state.data = res.data; + }), + ); + } + } + }, + init({ updatePath, data }) { + if (typeof data === 'string' && data) { + set( + produce((state) => { + state.code = data; + state.data = data; + state.dataType = 'string'; + state.updatePath = updatePath; + }), + ); + } else if (typeof data === 'object' && data) { + set( + produce((state) => { + state.data = data; + state.code = JSON.stringify(data, null, 2); + state.dataType = 'object'; + state.updatePath = updatePath; + }), + ); + } + }, +})); diff --git a/src/pages/container/preview/index.tsx b/src/pages/container/preview/index.tsx index f8e6784..131b438 100644 --- a/src/pages/container/preview/index.tsx +++ b/src/pages/container/preview/index.tsx @@ -1,14 +1,60 @@ -import { Container } from '@abearxiong/container'; +import { Container, ContainerEdit, RenderData } from '@abearxiong/container'; import { useEffect, useRef, useState } from 'react'; -import { useParams } from 'react-router'; -import { query } from '@/modules'; +import { replace, useParams } from 'react-router'; +import { query, ws, useStore } from '@/modules'; import { message } from 'antd'; +export const useListener = (id?: string, opts?: any) => { + const { refresh } = opts || {}; + const connected = useStore((state) => state.connected); + // 监听服务器的消息 + useEffect(() => { + if (!id) return; + if (!connected) return; + ws.send( + JSON.stringify({ + type: 'subscribe', + data: { + type: 'pageEdit', + data: { + cid: id, + // cids: [], + // pids:'', + }, + }, + }), + ); + ws.addEventListener('message', listener); + return () => { + if (!id) return; + if (!connected) return; + ws.removeEventListener('message', listener); + }; + }, [id, connected]); + const listener = (event) => { + const parseIfJson = (data: string) => { + try { + return JSON.parse(data); + } catch (e) { + return data; + } + }; + const receivedData = parseIfJson(event.data); + if (typeof receivedData === 'string') return; + if (receivedData.type === 'pageEdit' && receivedData.source === 'container') { + const { data: containerData } = receivedData; + if (containerData.id !== id) return; + if (refresh) { + refresh(containerData); + } + } + }; +}; export const Preview = () => { const params = useParams<{ id: string }>(); const id = params.id; const ref = useRef(null); - const containerRef = useRef(null); + const containerRef = useRef(null); const [data, setData] = useState({}); useEffect(() => { @@ -28,6 +74,7 @@ export const Preview = () => { const code = { id: data.id, title: data.title, + codeId: data.Id, code: data.code, data: data.data, }; @@ -36,14 +83,40 @@ export const Preview = () => { message.error(res.msg || 'Failed to fetch data'); } }; - const init = async (data: any[]) => { + const refresh = (data: any) => { + if (!data.id) return; + const code = { + id: data.id, + title: data.title, + codeId: data.Id, + code: data.code, + data: data.data, + hash: '', + }; + init([code], true); + }; + useListener(id, { refresh: refresh }); + const init = async (data: any[], replace: boolean = false) => { // console.log('data', data, ref.current); + if (containerRef.current) { + const container = containerRef.current; + console.log('data', data, container.data); + container.updateData(data); + await new Promise((resolve) => { + setTimeout(resolve, 2000); + }); + console.log('update---data', data, container.data); + container.destroy(id!); + container.renderId(id!); + return; + } + console.log('data', containerRef.current); const container = new Container({ root: ref.current!, data: data as any, showChild: false, }); - container.render(id!); + container.renderId(id!); containerRef.current = container; }; return ( diff --git a/src/pages/panel/deck/index.tsx b/src/pages/panel/deck/index.tsx index 186f2b7..5b8033f 100644 --- a/src/pages/panel/deck/index.tsx +++ b/src/pages/panel/deck/index.tsx @@ -43,22 +43,25 @@ export const Deck = () => { const codes = nodes.map((node: any) => { const container = node.container; const data = container?.data || {}; + const nodeData = node.data || {}; + let style = nodeData.style ?? { + position: 'absolute', + width: 100, + height: 100, + }; return { id: node.id, title: node.title, code: container?.code || '', data: data, children: node.children, - ...data, // style className shadowRoot showChild + // TODO: style className shadowRoot showChild + className: nodeData.className, + shadowRoot: nodeData.shadowRoot, + showChild: nodeData.showChild, + style, }; }); - // const code = { - // id: data.id, - // title: data.title, - // code: data.code, - // data: data.data, - // }; - // init([code]); init(codes); console.log('codes', codes); } diff --git a/src/pages/panel/edit/List.tsx b/src/pages/panel/edit/List.tsx index b587ecd..a6edbf6 100644 --- a/src/pages/panel/edit/List.tsx +++ b/src/pages/panel/edit/List.tsx @@ -5,7 +5,7 @@ import { useShallow } from 'zustand/react/shallow'; import { Form } from 'antd'; import copy from 'copy-to-clipboard'; import { useNavigate } from 'react-router'; - +import { useToCodeEditor } from '@/pages/code-editor'; const FormModal = () => { const [form] = Form.useForm(); @@ -69,6 +69,7 @@ const FormModal = () => { }; export const List = () => { const navicate = useNavigate(); + const toCodeEditor = useToCodeEditor(); const editStore = useEditStore( useShallow((state) => { return { @@ -134,6 +135,12 @@ export const List = () => { }}> Deck +