diff --git a/package.json b/package.json index f681f4cb..d4db1162 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "p-queue-cjs": "7.3.4", "protobufjs": "^7.2.3", "pstree.remy": "^1.1.8", + "react-hotkeys-hook": "^4.4.1", "reflect-metadata": "^0.1.13", "sequelize": "^6.25.5", "serve-handler": "^6.1.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 240ce1dd..a19e830b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + dependencies: '@grpc/grpc-js': specifier: ^1.8.13 @@ -94,6 +98,9 @@ dependencies: pstree.remy: specifier: ^1.1.8 version: 1.1.8 + react-hotkeys-hook: + specifier: ^4.4.1 + version: 4.4.1(react-dom@18.2.0)(react@18.2.0) reflect-metadata: specifier: ^0.1.13 version: 0.1.13 @@ -3694,6 +3701,7 @@ packages: /@gar/promisify@1.1.3: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + requiresBuild: true dev: false optional: true @@ -4128,6 +4136,7 @@ packages: /@npmcli/fs@1.1.1: resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} + requiresBuild: true dependencies: '@gar/promisify': 1.1.3 semver: 7.5.1 @@ -4138,6 +4147,7 @@ packages: resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} engines: {node: '>=10'} deprecated: This functionality has been moved to @npmcli/fs + requiresBuild: true dependencies: mkdirp: 1.0.4 rimraf: 3.0.2 @@ -6452,6 +6462,7 @@ packages: /are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + requiresBuild: true dependencies: delegates: 1.0.0 readable-stream: 3.6.2 @@ -7039,6 +7050,7 @@ packages: /cacache@15.3.0: resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} engines: {node: '>= 10'} + requiresBuild: true dependencies: '@npmcli/fs': 1.1.1 '@npmcli/move-file': 1.1.2 @@ -8266,11 +8278,13 @@ packages: /env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + requiresBuild: true dev: false optional: true /err-code@2.0.3: resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + requiresBuild: true dev: false optional: true @@ -9168,6 +9182,7 @@ packages: /gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + requiresBuild: true dependencies: aproba: 2.0.0 color-support: 1.1.3 @@ -9745,6 +9760,7 @@ packages: /infer-owner@1.0.4: resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + requiresBuild: true dev: false optional: true @@ -9996,6 +10012,7 @@ packages: /is-lambda@1.0.1: resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + requiresBuild: true dev: false optional: true @@ -10274,7 +10291,6 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} @@ -10729,7 +10745,6 @@ packages: hasBin: true dependencies: js-tokens: 4.0.0 - dev: true /lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} @@ -10792,6 +10807,7 @@ packages: /make-fetch-happen@9.1.0: resolution: {integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==} engines: {node: '>= 10'} + requiresBuild: true dependencies: agentkeepalive: 4.3.0 cacache: 15.3.0 @@ -11006,6 +11022,7 @@ packages: /minipass-collect@1.0.2: resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} engines: {node: '>= 8'} + requiresBuild: true dependencies: minipass: 3.3.6 dev: false @@ -11014,6 +11031,7 @@ packages: /minipass-fetch@1.4.1: resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==} engines: {node: '>=8'} + requiresBuild: true dependencies: minipass: 3.3.6 minipass-sized: 1.0.3 @@ -11026,6 +11044,7 @@ packages: /minipass-flush@1.0.5: resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} engines: {node: '>= 8'} + requiresBuild: true dependencies: minipass: 3.3.6 dev: false @@ -11034,6 +11053,7 @@ packages: /minipass-pipeline@1.2.4: resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} engines: {node: '>=8'} + requiresBuild: true dependencies: minipass: 3.3.6 dev: false @@ -11042,6 +11062,7 @@ packages: /minipass-sized@1.0.3: resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} engines: {node: '>=8'} + requiresBuild: true dependencies: minipass: 3.3.6 dev: false @@ -11413,6 +11434,7 @@ packages: /npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + requiresBuild: true dependencies: are-we-there-yet: 3.0.1 console-control-strings: 1.1.0 @@ -12517,6 +12539,7 @@ packages: /promise-inflight@1.0.1: resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + requiresBuild: true peerDependencies: bluebird: '*' peerDependenciesMeta: @@ -12528,6 +12551,7 @@ packages: /promise-retry@2.0.1: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} + requiresBuild: true dependencies: err-code: 2.0.3 retry: 0.12.0 @@ -12615,6 +12639,7 @@ packages: /prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + requiresBuild: true dev: true optional: true @@ -13680,7 +13705,6 @@ packages: loose-envify: 1.4.0 react: 18.2.0 scheduler: 0.23.0 - dev: true /react-easy-crop@4.7.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-oDi1375Jo/zuPUvo3oauxnNbfy8L4wsbmHD1KB2vT55fdgu+q8/K0w/rDWzy9jz4jfQ94Q9+3Yu366sDDFVmiA==} @@ -13747,6 +13771,21 @@ packages: shallowequal: 1.1.0 dev: true + /react-hotkeys-hook@4.4.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-sClBMBioFEgFGYLTWWRKvhxcCx1DRznd+wkFHwQZspnRBkHTgruKIHptlK/U/2DPX8BhHoRGzpMVWUXMmdZlmw==} + peerDependencies: + react: '>=16.8.1 || 18' + react-dom: '>=16.8.1 || 18' + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /react-intl-universal@2.6.21(react@18.2.0): resolution: {integrity: sha512-JJqZMzdB6jd4f0NfGRc9XM/pZElxtrDCWC9pE2yIesDO70SL+jQgaFAucQmstPwYqCcjvLpCgOrjP7cIo4kJnw==} requiresBuild: true @@ -13963,7 +14002,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - dev: true /reactcss@1.2.3(react@18.2.0): resolution: {integrity: sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==} @@ -14218,6 +14256,7 @@ packages: /retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} + requiresBuild: true dev: false optional: true @@ -14309,6 +14348,7 @@ packages: /sax@1.2.4: resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} + requiresBuild: true dev: true optional: true @@ -14322,7 +14362,6 @@ packages: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: loose-envify: 1.4.0 - dev: true /schema-utils@3.1.2: resolution: {integrity: sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==} @@ -14649,6 +14688,7 @@ packages: /socks-proxy-agent@6.2.1: resolution: {integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==} engines: {node: '>= 10'} + requiresBuild: true dependencies: agent-base: 6.0.2 debug: 4.3.4 @@ -14792,6 +14832,7 @@ packages: /ssri@8.0.1: resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} engines: {node: '>= 8'} + requiresBuild: true dependencies: minipass: 3.3.6 dev: false @@ -15703,6 +15744,7 @@ packages: /unique-filename@1.1.1: resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} + requiresBuild: true dependencies: unique-slug: 2.0.2 dev: false @@ -15710,6 +15752,7 @@ packages: /unique-slug@2.0.2: resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} + requiresBuild: true dependencies: imurmurhash: 0.1.4 dev: false diff --git a/src/pages/script/index.tsx b/src/pages/script/index.tsx index d9aeacc4..a459f380 100644 --- a/src/pages/script/index.tsx +++ b/src/pages/script/index.tsx @@ -44,12 +44,11 @@ import uniq from 'lodash/uniq'; import IconFont from '@/components/iconfont'; import RenameModal from './renameModal'; import { langs } from '@uiw/codemirror-extensions-langs'; - +import { useHotkeys } from 'react-hotkeys-hook'; const { Text } = Typography; const Script = () => { - const { headerStyle, isPhone, theme } = - useOutletContext(); + const { headerStyle, isPhone, theme } = useOutletContext(); const [value, setValue] = useState(intl.get('请选择脚本文件')); const [select, setSelect] = useState(''); const [data, setData] = useState([]); @@ -135,6 +134,10 @@ const Script = () => { const onTreeSelect = useCallback( (keys: Key[], e: any) => { + const node = e.node; + if (node.key === select && isEditing) { + return; + } const content = editorRef.current ? editorRef.current.getValue().replace(/\r\n/g, '\n') : value; @@ -155,7 +158,7 @@ const Script = () => { onSelect(keys[0], e.node); } }, - [value], + [value, select, isEditing], ); const onSearch = useCallback( @@ -187,6 +190,14 @@ const Script = () => { setExpandedKeys(expKeys); }; + const onDoubleClick = (e: any, node: any) => { + if (node.type === 'file') { + setSelect(node.key); + setCurrentNode(node); + setIsEditing(true); + } + }; + const editFile = () => { setTimeout(() => { setIsEditing(true); @@ -367,6 +378,16 @@ const Script = () => { } }, [treeDom.current, data]); + useHotkeys( + 'meta+s', + (e) => { + if (isEditing) { + saveFile(); + } + }, + { enableOnFormTags: ['textarea'], preventDefault: true }, + ); + const action = (key: string | number) => { switch (key) { case 'save': @@ -543,6 +564,7 @@ const Script = () => { onExpand={onExpand} showLine={{ showLeafIcon: true }} onSelect={onTreeSelect} + onDoubleClick={onDoubleClick} > @@ -591,15 +613,17 @@ const Script = () => { }} /> )} - {isLogModalVisible && { - setIsLogModalVisible(false); - }} - />} + {isLogModalVisible && ( + { + setIsLogModalVisible(false); + }} + /> + )}