feature/gui-configuration:支持从 GUI 配置程序。 #4
@ -12,8 +12,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.10.5",
|
"@emotion/react": "^11.10.5",
|
||||||
"@emotion/styled": "^11.10.5",
|
"@emotion/styled": "^11.10.5",
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
||||||
|
"@fortawesome/free-regular-svg-icons": "^6.2.1",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||||
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
|
"@mui/material": "^5.11.1",
|
||||||
"@tauri-apps/api": "^1.1.0",
|
"@tauri-apps/api": "^1.1.0",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
|
"ramda": "^0.28.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-async-hook": "^4.0.0",
|
"react-async-hook": "^4.0.0",
|
||||||
"react-dom": "^18.2.0"
|
"react-dom": "^18.2.0"
|
||||||
@ -24,6 +30,7 @@
|
|||||||
"@emotion/serialize": "^1.1.1",
|
"@emotion/serialize": "^1.1.1",
|
||||||
"@tauri-apps/cli": "^1.1.0",
|
"@tauri-apps/cli": "^1.1.0",
|
||||||
"@types/node": "^18.7.10",
|
"@types/node": "^18.7.10",
|
||||||
|
"@types/ramda": "^0.28.20",
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.0.15",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@vitejs/plugin-react": "^2.0.0",
|
"@vitejs/plugin-react": "^2.0.0",
|
||||||
|
281
pnpm-lock.yaml
generated
281
pnpm-lock.yaml
generated
@ -6,9 +6,15 @@ specifiers:
|
|||||||
'@emotion/react': ^11.10.5
|
'@emotion/react': ^11.10.5
|
||||||
'@emotion/serialize': ^1.1.1
|
'@emotion/serialize': ^1.1.1
|
||||||
'@emotion/styled': ^11.10.5
|
'@emotion/styled': ^11.10.5
|
||||||
|
'@fortawesome/fontawesome-svg-core': ^6.2.1
|
||||||
|
'@fortawesome/free-regular-svg-icons': ^6.2.1
|
||||||
|
'@fortawesome/free-solid-svg-icons': ^6.2.1
|
||||||
|
'@fortawesome/react-fontawesome': ^0.2.0
|
||||||
|
'@mui/material': ^5.11.1
|
||||||
'@tauri-apps/api': ^1.1.0
|
'@tauri-apps/api': ^1.1.0
|
||||||
'@tauri-apps/cli': ^1.1.0
|
'@tauri-apps/cli': ^1.1.0
|
||||||
'@types/node': ^18.7.10
|
'@types/node': ^18.7.10
|
||||||
|
'@types/ramda': ^0.28.20
|
||||||
'@types/react': ^18.0.15
|
'@types/react': ^18.0.15
|
||||||
'@types/react-dom': ^18.0.6
|
'@types/react-dom': ^18.0.6
|
||||||
'@vitejs/plugin-react': ^2.0.0
|
'@vitejs/plugin-react': ^2.0.0
|
||||||
@ -22,6 +28,7 @@ specifiers:
|
|||||||
eslint-plugin-simple-import-sort: ^8.0.0
|
eslint-plugin-simple-import-sort: ^8.0.0
|
||||||
postcss: ^8.4.19
|
postcss: ^8.4.19
|
||||||
prettier: ^2.7.1
|
prettier: ^2.7.1
|
||||||
|
ramda: ^0.28.0
|
||||||
react: ^18.2.0
|
react: ^18.2.0
|
||||||
react-async-hook: ^4.0.0
|
react-async-hook: ^4.0.0
|
||||||
react-dom: ^18.2.0
|
react-dom: ^18.2.0
|
||||||
@ -33,8 +40,14 @@ specifiers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@emotion/react': 11.10.5_kzbn2opkn2327fwg5yzwzya5o4
|
'@emotion/react': 11.10.5_kzbn2opkn2327fwg5yzwzya5o4
|
||||||
'@emotion/styled': 11.10.5_qvatmowesywn4ye42qoh247szu
|
'@emotion/styled': 11.10.5_qvatmowesywn4ye42qoh247szu
|
||||||
|
'@fortawesome/fontawesome-svg-core': 6.2.1
|
||||||
|
'@fortawesome/free-regular-svg-icons': 6.2.1
|
||||||
|
'@fortawesome/free-solid-svg-icons': 6.2.1
|
||||||
|
'@fortawesome/react-fontawesome': 0.2.0_z27bm67dtmuyyvss23ckjdrcuy
|
||||||
|
'@mui/material': 5.11.1_lskpmcsdi7ipu6qpuapyu56ihm
|
||||||
'@tauri-apps/api': 1.2.0
|
'@tauri-apps/api': 1.2.0
|
||||||
clsx: 1.2.1
|
clsx: 1.2.1
|
||||||
|
ramda: 0.28.0
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-async-hook: 4.0.0_react@18.2.0
|
react-async-hook: 4.0.0_react@18.2.0
|
||||||
react-dom: 18.2.0_react@18.2.0
|
react-dom: 18.2.0_react@18.2.0
|
||||||
@ -45,6 +58,7 @@ devDependencies:
|
|||||||
'@emotion/serialize': 1.1.1
|
'@emotion/serialize': 1.1.1
|
||||||
'@tauri-apps/cli': 1.2.2
|
'@tauri-apps/cli': 1.2.2
|
||||||
'@types/node': 18.11.16
|
'@types/node': 18.11.16
|
||||||
|
'@types/ramda': 0.28.20
|
||||||
'@types/react': 18.0.26
|
'@types/react': 18.0.26
|
||||||
'@types/react-dom': 18.0.9
|
'@types/react-dom': 18.0.9
|
||||||
'@vitejs/plugin-react': 2.2.0_vite@3.2.5
|
'@vitejs/plugin-react': 2.2.0_vite@3.2.5
|
||||||
@ -505,6 +519,47 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
/@fortawesome/fontawesome-common-types/6.2.1:
|
||||||
|
resolution: {integrity: sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@fortawesome/fontawesome-svg-core/6.2.1:
|
||||||
|
resolution: {integrity: sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
'@fortawesome/fontawesome-common-types': 6.2.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@fortawesome/free-regular-svg-icons/6.2.1:
|
||||||
|
resolution: {integrity: sha512-wiqcNDNom75x+pe88FclpKz7aOSqS2lOivZeicMV5KRwOAeypxEYWAK/0v+7r+LrEY30+qzh8r2XDaEHvoLsMA==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
'@fortawesome/fontawesome-common-types': 6.2.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@fortawesome/free-solid-svg-icons/6.2.1:
|
||||||
|
resolution: {integrity: sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
'@fortawesome/fontawesome-common-types': 6.2.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@fortawesome/react-fontawesome/0.2.0_z27bm67dtmuyyvss23ckjdrcuy:
|
||||||
|
resolution: {integrity: sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@fortawesome/fontawesome-svg-core': ~1 || ~6
|
||||||
|
react: '>=16.3'
|
||||||
|
dependencies:
|
||||||
|
'@fortawesome/fontawesome-svg-core': 6.2.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@jridgewell/gen-mapping/0.1.1:
|
/@jridgewell/gen-mapping/0.1.1:
|
||||||
resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
|
resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
|
||||||
engines: {node: '>=6.0.0'}
|
engines: {node: '>=6.0.0'}
|
||||||
@ -543,6 +598,164 @@ packages:
|
|||||||
'@jridgewell/sourcemap-codec': 1.4.14
|
'@jridgewell/sourcemap-codec': 1.4.14
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@mui/base/5.0.0-alpha.111_ib3m5ricvtkl2cll7qpr2f6lvq:
|
||||||
|
resolution: {integrity: sha512-2wfIPpl97S4dPzD0QOM3UIzQ/EuXCYQvHmXxTpfKxev/cfkzOe7Ik/McoYUBbtM1bSOqH3W276R/L2LF9cyXqQ==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0
|
||||||
|
react-dom: ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.20.6
|
||||||
|
'@emotion/is-prop-valid': 1.2.0
|
||||||
|
'@mui/types': 7.2.3_@types+react@18.0.26
|
||||||
|
'@mui/utils': 5.11.1_react@18.2.0
|
||||||
|
'@popperjs/core': 2.11.6
|
||||||
|
'@types/react': 18.0.26
|
||||||
|
clsx: 1.2.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0_react@18.2.0
|
||||||
|
react-is: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@mui/core-downloads-tracker/5.11.1:
|
||||||
|
resolution: {integrity: sha512-QVqVNlZ2K+LqUDE5kFgYd0r4KekR/dv2cNYbAutQWbfOA8VPVUVrDz0ELrEcoe8TjM/CwnsmGvaDh/YSNl/ALA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@mui/material/5.11.1_lskpmcsdi7ipu6qpuapyu56ihm:
|
||||||
|
resolution: {integrity: sha512-yaZiXvcrl2vgUK+VO24780BWRgwdAMmAyuMVZnRTts1Yu0tWd6PjIYq2ZtaOlpj6/LbaSS+Q2kSfxYnDQ20CEQ==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/react': ^11.5.0
|
||||||
|
'@emotion/styled': ^11.3.0
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0
|
||||||
|
react-dom: ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@emotion/react':
|
||||||
|
optional: true
|
||||||
|
'@emotion/styled':
|
||||||
|
optional: true
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.20.6
|
||||||
|
'@emotion/react': 11.10.5_kzbn2opkn2327fwg5yzwzya5o4
|
||||||
|
'@emotion/styled': 11.10.5_qvatmowesywn4ye42qoh247szu
|
||||||
|
'@mui/base': 5.0.0-alpha.111_ib3m5ricvtkl2cll7qpr2f6lvq
|
||||||
|
'@mui/core-downloads-tracker': 5.11.1
|
||||||
|
'@mui/system': 5.11.1_ogriz7mfahdh34qnfautfro5yu
|
||||||
|
'@mui/types': 7.2.3_@types+react@18.0.26
|
||||||
|
'@mui/utils': 5.11.1_react@18.2.0
|
||||||
|
'@types/react': 18.0.26
|
||||||
|
'@types/react-transition-group': 4.4.5
|
||||||
|
clsx: 1.2.1
|
||||||
|
csstype: 3.1.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0_react@18.2.0
|
||||||
|
react-is: 18.2.0
|
||||||
|
react-transition-group: 4.4.5_biqbaboplfbrettd7655fr4n2y
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@mui/private-theming/5.11.1_kzbn2opkn2327fwg5yzwzya5o4:
|
||||||
|
resolution: {integrity: sha512-nnHg7kA5RwFRhy0wiDYe59sLCVGORpPypL1JcEdhv0+N0Zbmc2E/y4z2zqMRZ62MAEscpro7cQbvv244ThA84A==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.20.6
|
||||||
|
'@mui/utils': 5.11.1_react@18.2.0
|
||||||
|
'@types/react': 18.0.26
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@mui/styled-engine/5.11.0_dovxhg2tvkkxkdnqyoum6wzcxm:
|
||||||
|
resolution: {integrity: sha512-AF06K60Zc58qf0f7X+Y/QjaHaZq16znliLnGc9iVrV/+s8Ln/FCoeNuFvhlCbZZQ5WQcJvcy59zp0nXrklGGPQ==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/react': ^11.4.1
|
||||||
|
'@emotion/styled': ^11.3.0
|
||||||
|
react: ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@emotion/react':
|
||||||
|
optional: true
|
||||||
|
'@emotion/styled':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.20.6
|
||||||
|
'@emotion/cache': 11.10.5
|
||||||
|
'@emotion/react': 11.10.5_kzbn2opkn2327fwg5yzwzya5o4
|
||||||
|
'@emotion/styled': 11.10.5_qvatmowesywn4ye42qoh247szu
|
||||||
|
csstype: 3.1.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@mui/system/5.11.1_ogriz7mfahdh34qnfautfro5yu:
|
||||||
|
resolution: {integrity: sha512-BEA2S0hay8n8CcZftkeAVsi0nsb5ZjdnZRCahv5lX7QJYwDjO4ucJ6lnvxHe2v/9Te1LLjTO7ojxu/qM6CE5Cg==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@emotion/react': ^11.5.0
|
||||||
|
'@emotion/styled': ^11.3.0
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@emotion/react':
|
||||||
|
optional: true
|
||||||
|
'@emotion/styled':
|
||||||
|
optional: true
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.20.6
|
||||||
|
'@emotion/react': 11.10.5_kzbn2opkn2327fwg5yzwzya5o4
|
||||||
|
'@emotion/styled': 11.10.5_qvatmowesywn4ye42qoh247szu
|
||||||
|
'@mui/private-theming': 5.11.1_kzbn2opkn2327fwg5yzwzya5o4
|
||||||
|
'@mui/styled-engine': 5.11.0_dovxhg2tvkkxkdnqyoum6wzcxm
|
||||||
|
'@mui/types': 7.2.3_@types+react@18.0.26
|
||||||
|
'@mui/utils': 5.11.1_react@18.2.0
|
||||||
|
'@types/react': 18.0.26
|
||||||
|
clsx: 1.2.1
|
||||||
|
csstype: 3.1.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@mui/types/7.2.3_@types+react@18.0.26:
|
||||||
|
resolution: {integrity: sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@types/react':
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.0.26
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@mui/utils/5.11.1_react@18.2.0:
|
||||||
|
resolution: {integrity: sha512-lMAPgIJoil8V9ZxsMbEflMsvZmWcHbRVMc4JDY9jPO9V4welpF43h/O267b1RqlcRnC5MEbVQV605GYkTZY29Q==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^17.0.0 || ^18.0.0
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.20.6
|
||||||
|
'@types/prop-types': 15.7.5
|
||||||
|
'@types/react-is': 17.0.3
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
react-is: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@nodelib/fs.scandir/2.1.5:
|
/@nodelib/fs.scandir/2.1.5:
|
||||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
@ -564,6 +777,10 @@ packages:
|
|||||||
fastq: 1.14.0
|
fastq: 1.14.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@popperjs/core/2.11.6:
|
||||||
|
resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@tauri-apps/api/1.2.0:
|
/@tauri-apps/api/1.2.0:
|
||||||
resolution: {integrity: sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==}
|
resolution: {integrity: sha512-lsI54KI6HGf7VImuf/T9pnoejfgkNoXveP14pVV7XarrQ46rOejIVJLFqHI9sRReJMGdh2YuCoI3cc/yCWCsrw==}
|
||||||
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
|
engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'}
|
||||||
@ -680,12 +897,30 @@ packages:
|
|||||||
/@types/prop-types/15.7.5:
|
/@types/prop-types/15.7.5:
|
||||||
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||||
|
|
||||||
|
/@types/ramda/0.28.20:
|
||||||
|
resolution: {integrity: sha512-MeUhzGSXQTRsY19JGn5LIBTLxVEnyF6HDNr08KSJqybsm4DlfLIgK1jBHjhpiSyk252tXYmp+UOe0UFg0UiFsA==}
|
||||||
|
dependencies:
|
||||||
|
ts-toolbelt: 6.15.5
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/react-dom/18.0.9:
|
/@types/react-dom/18.0.9:
|
||||||
resolution: {integrity: sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg==}
|
resolution: {integrity: sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 18.0.26
|
'@types/react': 18.0.26
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/react-is/17.0.3:
|
||||||
|
resolution: {integrity: sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==}
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.0.26
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@types/react-transition-group/4.4.5:
|
||||||
|
resolution: {integrity: sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==}
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.0.26
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@types/react/18.0.26:
|
/@types/react/18.0.26:
|
||||||
resolution: {integrity: sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==}
|
resolution: {integrity: sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -1039,6 +1274,13 @@ packages:
|
|||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/dom-helpers/5.2.1:
|
||||||
|
resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.20.6
|
||||||
|
csstype: 3.1.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/electron-to-chromium/1.4.284:
|
/electron-to-chromium/1.4.284:
|
||||||
resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==}
|
resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==}
|
||||||
dev: true
|
dev: true
|
||||||
@ -1840,6 +2082,11 @@ packages:
|
|||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/object-assign/4.1.1:
|
||||||
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/object-hash/3.0.0:
|
/object-hash/3.0.0:
|
||||||
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
|
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
@ -1992,6 +2239,14 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/prop-types/15.8.1:
|
||||||
|
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
|
||||||
|
dependencies:
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
object-assign: 4.1.1
|
||||||
|
react-is: 16.13.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/queue-microtask/1.2.3:
|
/queue-microtask/1.2.3:
|
||||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||||
dev: true
|
dev: true
|
||||||
@ -2001,6 +2256,10 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/ramda/0.28.0:
|
||||||
|
resolution: {integrity: sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-async-hook/4.0.0_react@18.2.0:
|
/react-async-hook/4.0.0_react@18.2.0:
|
||||||
resolution: {integrity: sha512-97lgjFkOcHCTYSrsKBpsXg3iVWM0LnzedB749iP76sb3/8Ouu4nHIkCLEOrQWHVYqrYxjF05NN6GHoXWFkB3Kw==}
|
resolution: {integrity: sha512-97lgjFkOcHCTYSrsKBpsXg3iVWM0LnzedB749iP76sb3/8Ouu4nHIkCLEOrQWHVYqrYxjF05NN6GHoXWFkB3Kw==}
|
||||||
engines: {node: '>=8', npm: '>=5'}
|
engines: {node: '>=8', npm: '>=5'}
|
||||||
@ -2024,11 +2283,29 @@ packages:
|
|||||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/react-is/18.2.0:
|
||||||
|
resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react-refresh/0.14.0:
|
/react-refresh/0.14.0:
|
||||||
resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==}
|
resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/react-transition-group/4.4.5_biqbaboplfbrettd7655fr4n2y:
|
||||||
|
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.6.0'
|
||||||
|
react-dom: '>=16.6.0'
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.20.6
|
||||||
|
dom-helpers: 5.2.1
|
||||||
|
loose-envify: 1.4.0
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0_react@18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/react/18.2.0:
|
/react/18.2.0:
|
||||||
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
|
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -2221,6 +2498,10 @@ packages:
|
|||||||
is-number: 7.0.0
|
is-number: 7.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/ts-toolbelt/6.15.5:
|
||||||
|
resolution: {integrity: sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/tsconfig-paths/3.14.1:
|
/tsconfig-paths/3.14.1:
|
||||||
resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==}
|
resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use futures::{future::join_all, stream::FuturesUnordered, StreamExt};
|
use futures::future::join_all;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use paris::info;
|
use paris::info;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::value::Index;
|
|
||||||
use std::{collections::HashMap, iter::Map, sync::Arc, thread, time::Duration};
|
use std::{collections::HashMap, sync::Arc, time::Duration};
|
||||||
use tauri::async_runtime::RwLock;
|
use tauri::async_runtime::RwLock;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
join,
|
join,
|
||||||
|
@ -11,6 +11,7 @@ mod rpc;
|
|||||||
use crate::core::AmbientLightMode;
|
use crate::core::AmbientLightMode;
|
||||||
use crate::core::CoreManager;
|
use crate::core::CoreManager;
|
||||||
use paris::*;
|
use paris::*;
|
||||||
|
use picker::config::DisplayConfig;
|
||||||
use picker::manager::Picker;
|
use picker::manager::Picker;
|
||||||
use picker::screenshot::ScreenshotDto;
|
use picker::screenshot::ScreenshotDto;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
@ -35,6 +36,26 @@ async fn take_snapshot() -> Vec<ScreenshotDto> {
|
|||||||
base64_bitmap_list
|
base64_bitmap_list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
async fn get_screenshot_by_config(config: DisplayConfig) -> Result<ScreenshotDto, String> {
|
||||||
|
info!("Hi");
|
||||||
|
let manager = Picker::global();
|
||||||
|
|
||||||
|
let start = time::Instant::now();
|
||||||
|
let screenshot_dto = manager.get_screenshot_by_config(config).await;
|
||||||
|
info!("截图耗时 {} s", start.elapsed().as_seconds_f32());
|
||||||
|
match screenshot_dto {
|
||||||
|
Ok(screenshot_dto) => {
|
||||||
|
info!("截图耗时 {} s", start.elapsed().as_seconds_f32());
|
||||||
|
Ok(screenshot_dto)
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
error!("get_screenshot_by_config failed. {}", error);
|
||||||
|
Err(format!("get_screenshot_by_config failed. {}", error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn get_picker_config() -> picker::config::Configuration {
|
fn get_picker_config() -> picker::config::Configuration {
|
||||||
let configuration = picker::config::Manager::global().get_config();
|
let configuration = picker::config::Manager::global().get_config();
|
||||||
@ -57,6 +78,7 @@ async fn main() {
|
|||||||
take_snapshot,
|
take_snapshot,
|
||||||
play_mode,
|
play_mode,
|
||||||
get_picker_config,
|
get_picker_config,
|
||||||
|
get_screenshot_by_config,
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
@ -9,6 +9,7 @@ pub struct LedStripConfig {
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||||
pub struct DisplayConfig {
|
pub struct DisplayConfig {
|
||||||
|
pub id: usize,
|
||||||
pub index_of_display: usize,
|
pub index_of_display: usize,
|
||||||
pub display_width: usize,
|
pub display_width: usize,
|
||||||
pub display_height: usize,
|
pub display_height: usize,
|
||||||
@ -19,8 +20,9 @@ pub struct DisplayConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayConfig {
|
impl DisplayConfig {
|
||||||
pub fn default(index_of_display: usize, display_width: usize, display_height: usize) -> Self {
|
pub fn default(id: usize, index_of_display: usize, display_width: usize, display_height: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
id,
|
||||||
index_of_display,
|
index_of_display,
|
||||||
display_width,
|
display_width,
|
||||||
display_height,
|
display_height,
|
||||||
|
@ -2,7 +2,7 @@ use futures::{stream::FuturesUnordered, StreamExt};
|
|||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use paris::info;
|
use paris::info;
|
||||||
use scrap::Display;
|
use scrap::Display;
|
||||||
use std::{borrow::Borrow, sync::Arc};
|
use std::sync::Arc;
|
||||||
use tokio::{sync::Mutex, task};
|
use tokio::{sync::Mutex, task};
|
||||||
|
|
||||||
use crate::picker::{config, screen::Screen};
|
use crate::picker::{config, screen::Screen};
|
||||||
@ -44,7 +44,7 @@ impl Picker {
|
|||||||
for (index, display) in displays.iter().enumerate() {
|
for (index, display) in displays.iter().enumerate() {
|
||||||
let height = display.height();
|
let height = display.height();
|
||||||
let width = display.width();
|
let width = display.width();
|
||||||
let config = DisplayConfig::default(index, width, height);
|
let config = DisplayConfig::default(index, index, width, height);
|
||||||
configs.push(config);
|
configs.push(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,4 +76,16 @@ impl Picker {
|
|||||||
|
|
||||||
anyhow::Ok(screenshot.to_dto().await)
|
anyhow::Ok(screenshot.to_dto().await)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_screenshot_by_config(
|
||||||
|
&self,
|
||||||
|
config: DisplayConfig,
|
||||||
|
) -> anyhow::Result<ScreenshotDto> {
|
||||||
|
let start = time::Instant::now();
|
||||||
|
let mut picker = DisplayPicker::from_config(config)?;
|
||||||
|
let screenshot = picker.take_screenshot()?;
|
||||||
|
info!("Take Screenshot Spend: {}", start.elapsed());
|
||||||
|
|
||||||
|
anyhow::Ok(screenshot.to_dto().await)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
83
src-tauri/src/picker/preview_manager.rs
Normal file
83
src-tauri/src/picker/preview_manager.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
use futures::{stream::FuturesUnordered, StreamExt};
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use paris::{info, warn};
|
||||||
|
use scrap::Display;
|
||||||
|
use std::{borrow::Borrow, sync::Arc};
|
||||||
|
use tokio::{sync::Mutex, task};
|
||||||
|
|
||||||
|
use crate::picker::{config, screen::Screen};
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
config::DisplayConfig,
|
||||||
|
display_picker::DisplayPicker,
|
||||||
|
manager::Picker,
|
||||||
|
screenshot::{Screenshot, ScreenshotDto},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct PreviewPicker {
|
||||||
|
pub pickers: Arc<Mutex<Vec<Arc<Mutex<DisplayPicker>>>>>,
|
||||||
|
pub screenshots: Arc<Mutex<Vec<Screenshot>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PreviewPicker {
|
||||||
|
pub fn global() -> &'static PreviewPicker {
|
||||||
|
static SCREEN_COLOR_PREVIEW_PICKER: OnceCell<PreviewPicker> = OnceCell::new();
|
||||||
|
|
||||||
|
SCREEN_COLOR_PREVIEW_PICKER.get_or_init(|| PreviewPicker {
|
||||||
|
pickers: Arc::new(Mutex::new(vec![])),
|
||||||
|
screenshots: Arc::new(Mutex::new(vec![])),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn list_displays(&self) {
|
||||||
|
let mut pickers = self.pickers.lock().await;
|
||||||
|
let displays = Display::all()
|
||||||
|
.map_err(|error| anyhow::anyhow!("Can not get all of displays. {}", error))?;
|
||||||
|
|
||||||
|
let mut configs = vec![];
|
||||||
|
let mut futs = FuturesUnordered::new();
|
||||||
|
|
||||||
|
for (index, display) in displays.iter().enumerate() {
|
||||||
|
let height = display.height();
|
||||||
|
let width = display.width();
|
||||||
|
let config = DisplayConfig::default(index, width, height);
|
||||||
|
configs.push(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
for config in configs.iter() {
|
||||||
|
let picker = DisplayPicker::from_config(*config);
|
||||||
|
match picker {
|
||||||
|
Ok(picker) => {
|
||||||
|
pickers.push(Arc::new(Mutex::new(picker)));
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
warn!(
|
||||||
|
"can not create DisplayPicker from config. config: {:?}",
|
||||||
|
config
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_screenshot_by_config(
|
||||||
|
&self,
|
||||||
|
config: DisplayConfig,
|
||||||
|
) -> anyhow::Result<ScreenshotDto> {
|
||||||
|
let start = time::Instant::now();
|
||||||
|
let mut picker = DisplayPicker::from_config(config)?;
|
||||||
|
let screenshot = picker.take_screenshot()?;
|
||||||
|
info!("Take Screenshot Spend: {}", start.elapsed());
|
||||||
|
|
||||||
|
anyhow::Ok(screenshot.to_dto().await)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn preview_display_by_config(config: DisplayConfig) -> anyhow::Result<ScreenshotDto> {
|
||||||
|
let start = time::Instant::now();
|
||||||
|
let mut picker = DisplayPicker::from_config(config)?;
|
||||||
|
let screenshot = picker.take_screenshot()?;
|
||||||
|
info!("Take Screenshot Spend: {}", start.elapsed());
|
||||||
|
|
||||||
|
anyhow::Ok(screenshot.to_dto().await)
|
||||||
|
}
|
||||||
|
}
|
@ -51,7 +51,7 @@ impl Screenshot {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let bottom: Vec<LedSamplePoints> = match config.top_led_strip {
|
let bottom: Vec<LedSamplePoints> = match config.bottom_led_strip {
|
||||||
Some(led_strip_config) => {
|
Some(led_strip_config) => {
|
||||||
let points = Self::get_one_edge_sample_points(
|
let points = Self::get_one_edge_sample_points(
|
||||||
config.display_height / 9,
|
config.display_height / 9,
|
||||||
@ -76,7 +76,7 @@ impl Screenshot {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let left: Vec<LedSamplePoints> = match config.top_led_strip {
|
let left: Vec<LedSamplePoints> = match config.left_led_strip {
|
||||||
Some(led_strip_config) => {
|
Some(led_strip_config) => {
|
||||||
let points = Self::get_one_edge_sample_points(
|
let points = Self::get_one_edge_sample_points(
|
||||||
config.display_width / 16,
|
config.display_width / 16,
|
||||||
@ -98,7 +98,7 @@ impl Screenshot {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let right: Vec<LedSamplePoints> = match config.top_led_strip {
|
let right: Vec<LedSamplePoints> = match config.right_led_strip {
|
||||||
Some(led_strip_config) => {
|
Some(led_strip_config) => {
|
||||||
let points = Self::get_one_edge_sample_points(
|
let points = Self::get_one_edge_sample_points(
|
||||||
config.display_width / 16,
|
config.display_width / 16,
|
||||||
@ -113,7 +113,7 @@ impl Screenshot {
|
|||||||
.map(|groups| -> Vec<Point> {
|
.map(|groups| -> Vec<Point> {
|
||||||
groups
|
groups
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(x, y)| (y, config.display_width - x))
|
.map(|(x, y)| (config.display_width - y, x))
|
||||||
.collect()
|
.collect()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
@ -145,14 +145,15 @@ impl Screenshot {
|
|||||||
let point_y_list: Vec<usize> = (point_start_y..width).step_by(cell_size_y).collect();
|
let point_y_list: Vec<usize> = (point_start_y..width).step_by(cell_size_y).collect();
|
||||||
let point_x_list: Vec<usize> = iter::successors(Some(point_start_x), |i| {
|
let point_x_list: Vec<usize> = iter::successors(Some(point_start_x), |i| {
|
||||||
let next = i + cell_size_x;
|
let next = i + cell_size_x;
|
||||||
(next < (width as f64)).then_some(next)
|
(next < (length as f64)).then_some(next)
|
||||||
})
|
})
|
||||||
.map(|i| i as usize)
|
.map(|i| i as usize)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let points: Vec<Point> = point_x_list
|
let points: Vec<Point> = point_x_list
|
||||||
.into_iter()
|
.iter()
|
||||||
.zip(point_y_list.into_iter())
|
.map(|&x| point_y_list.iter().map(move |&y| (x, y)))
|
||||||
|
.flatten()
|
||||||
.collect();
|
.collect();
|
||||||
points
|
points
|
||||||
.chunks(single_axis_points * single_axis_points)
|
.chunks(single_axis_points * single_axis_points)
|
||||||
|
58
src/App.tsx
58
src/App.tsx
@ -1,9 +1,10 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import reactLogo from './assets/react.svg';
|
import tw from 'twin.macro';
|
||||||
import { invoke } from '@tauri-apps/api/tauri';
|
import { invoke } from '@tauri-apps/api/tauri';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { Configurator } from './configurator/configurator';
|
import { Configurator } from './configurator/configurator';
|
||||||
|
import { ButtonSwitch } from './commons/components/button';
|
||||||
|
|
||||||
type Mode = 'Flowing' | 'Follow' | null;
|
type Mode = 'Flowing' | 'Follow' | null;
|
||||||
|
|
||||||
@ -39,63 +40,30 @@ function App() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="flex justify-between">
|
<div tw="flex justify-between">
|
||||||
{ledStripColors.map((it) => (
|
{ledStripColors.map((it) => (
|
||||||
<span className=" h-8 flex-auto" style={{ backgroundColor: it }}></span>
|
<span tw="h-8 flex-auto" style={{ backgroundColor: it }}></span>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-1 justify-center w-screen overflow-hidden">
|
<div tw="flex gap-1 justify-center w-screen overflow-hidden">
|
||||||
{screenshots.map((screenshot) => (
|
{screenshots.map((screenshot) => (
|
||||||
<div className="flex-auto">
|
<div tw="flex-auto">
|
||||||
<img src={screenshot} />
|
<img src={screenshot} />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-5 justify-center ">
|
<div tw="flex gap-5 justify-center ">
|
||||||
<button
|
<ButtonSwitch onClick={() => takeSnapshot()}>Take Snapshot</ButtonSwitch>
|
||||||
className="bg-black bg-opacity-20"
|
<ButtonSwitch onClick={() => getLedStripColors()}>Get Colors</ButtonSwitch>
|
||||||
type="button"
|
<ButtonSwitch onClick={() => switchCurrentMode('Flowing')}>
|
||||||
onClick={() => readPickerConfig()}
|
|
||||||
>
|
|
||||||
Refresh Displays
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="bg-black bg-opacity-20"
|
|
||||||
type="button"
|
|
||||||
onClick={() => takeSnapshot()}
|
|
||||||
>
|
|
||||||
Take Snapshot
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className="bg-black bg-opacity-20"
|
|
||||||
type="button"
|
|
||||||
onClick={() => getLedStripColors()}
|
|
||||||
>
|
|
||||||
Get Colors
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className={clsx('bg-black', 'bg-opacity-20', {
|
|
||||||
'bg-gradient-to-r from-purple-500 to-blue-500': currentMode === 'Flowing',
|
|
||||||
})}
|
|
||||||
type="button"
|
|
||||||
onClick={() => switchCurrentMode('Flowing')}
|
|
||||||
>
|
|
||||||
Flowing Light
|
Flowing Light
|
||||||
</button>
|
</ButtonSwitch>
|
||||||
<button
|
<ButtonSwitch onClick={() => switchCurrentMode('Follow')}>Follow</ButtonSwitch>
|
||||||
className={clsx('bg-black', 'bg-opacity-20', {
|
|
||||||
'bg-gradient-to-r from-purple-500 to-blue-500': currentMode === 'Follow',
|
|
||||||
})}
|
|
||||||
type="button"
|
|
||||||
onClick={() => switchCurrentMode('Follow')}
|
|
||||||
>
|
|
||||||
Follow
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-5 justify-center">
|
<div tw="flex gap-5 justify-center">
|
||||||
<Configurator />
|
<Configurator />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
21
src/commons/components/button.tsx
Normal file
21
src/commons/components/button.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import tw, { theme } from 'twin.macro';
|
||||||
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
|
interface ButtonProps {
|
||||||
|
value?: boolean;
|
||||||
|
isSmall?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ButtonSwitch = styled.button(({ value, isSmall }: ButtonProps) => [
|
||||||
|
// The common button styles
|
||||||
|
tw`px-8 py-2 rounded-xl transform duration-75 dark:bg-black m-2 shadow-lg text-opacity-95 dark:shadow-gray-800`,
|
||||||
|
|
||||||
|
tw`hover:(scale-105)`,
|
||||||
|
tw`focus:(scale-100)`,
|
||||||
|
|
||||||
|
value && 'bg-gradient-to-r from-purple-500 to-blue-500',
|
||||||
|
|
||||||
|
isSmall ? tw`text-sm` : tw`text-lg`,
|
||||||
|
]);
|
@ -1,25 +1,97 @@
|
|||||||
import { HTMLAttributes } from 'react';
|
import { HTMLAttributes, useCallback, useMemo } from 'react';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { DisplayConfig } from '../models/display-config';
|
import { DisplayConfig } from '../models/display-config';
|
||||||
import { LedStrip } from './led-strip';
|
import { LedStrip } from './led-strip';
|
||||||
|
import tw, { css, styled, theme } from 'twin.macro';
|
||||||
|
import { ScreenshotDto } from '../models/screenshot.dto';
|
||||||
|
import { LedStripEditor } from './led-strip-editor';
|
||||||
|
import { LedStripConfig } from '../models/led-strip-config';
|
||||||
|
|
||||||
export interface DisplayWithLedStripsProps extends HTMLAttributes<HTMLElement> {
|
export interface DisplayWithLedStripsProps
|
||||||
|
extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {
|
||||||
config: DisplayConfig;
|
config: DisplayConfig;
|
||||||
screenshot: string;
|
screenshot: ScreenshotDto;
|
||||||
|
onChange?: (config: DisplayConfig) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const StyledContainer = styled.section(
|
||||||
|
tw`m-4 grid gap-1`,
|
||||||
|
css`
|
||||||
|
grid-template-columns: ${theme`width.5`} ${theme`width.3`} auto ${theme`width.3`} ${theme`width.5`};
|
||||||
|
`,
|
||||||
|
css`
|
||||||
|
grid-template-rows: ${theme`width.5`} ${theme`width.3`} auto ${theme`width.3`} ${theme`width.5`};
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
|
||||||
export const DisplayWithLedStrips: FC<DisplayWithLedStripsProps> = ({
|
export const DisplayWithLedStrips: FC<DisplayWithLedStripsProps> = ({
|
||||||
config,
|
config,
|
||||||
screenshot,
|
screenshot,
|
||||||
|
onChange,
|
||||||
...htmlAttrs
|
...htmlAttrs
|
||||||
}) => {
|
}) => {
|
||||||
|
const screenshotUrl = useMemo(
|
||||||
|
() => `data:image/png;base64,${screenshot.encode_image}`,
|
||||||
|
[screenshot.encode_image],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onLedStripConfigChange = useCallback(
|
||||||
|
(
|
||||||
|
position:
|
||||||
|
| 'top_led_strip'
|
||||||
|
| 'left_led_strip'
|
||||||
|
| 'right_led_strip'
|
||||||
|
| 'bottom_led_strip',
|
||||||
|
value: LedStripConfig | null,
|
||||||
|
) => {
|
||||||
|
const c = { ...config, [position]: value };
|
||||||
|
onChange?.(c);
|
||||||
|
},
|
||||||
|
[config],
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<section className="m-4 grid grid-rows-3 grid-cols-3 gr" {...htmlAttrs}>
|
<StyledContainer {...htmlAttrs}>
|
||||||
<img src={screenshot} className="row-start-2 col-start-2" />
|
<img src={screenshotUrl} tw="row-start-3 col-start-3" />
|
||||||
<LedStrip config={config.top_led_strip} className="row-start-1 col-start-2 h-1" />
|
<LedStrip
|
||||||
<LedStrip config={config.left_led_strip} className="row-start-2 col-start-1 w-1" />
|
config={config.top_led_strip}
|
||||||
<LedStrip config={config.right_led_strip} className="row-start-2 col-start-3" />
|
colors={screenshot.colors.top}
|
||||||
<LedStrip config={config.bottom_led_strip} className="row-start-3 col-start-2" />
|
tw="row-start-2 col-start-3"
|
||||||
</section>
|
/>
|
||||||
|
<LedStrip
|
||||||
|
config={config.left_led_strip}
|
||||||
|
colors={screenshot.colors.left}
|
||||||
|
tw="row-start-3 col-start-2"
|
||||||
|
/>
|
||||||
|
<LedStrip
|
||||||
|
config={config.right_led_strip}
|
||||||
|
colors={screenshot.colors.right}
|
||||||
|
tw="row-start-3 col-start-4"
|
||||||
|
/>
|
||||||
|
<LedStrip
|
||||||
|
config={config.bottom_led_strip}
|
||||||
|
colors={screenshot.colors.bottom}
|
||||||
|
tw="row-start-4 col-start-3"
|
||||||
|
/>
|
||||||
|
<LedStripEditor
|
||||||
|
config={config.top_led_strip}
|
||||||
|
tw="row-start-1 col-start-3"
|
||||||
|
onChange={(value) => onLedStripConfigChange('top_led_strip', value)}
|
||||||
|
/>
|
||||||
|
<LedStripEditor
|
||||||
|
config={config.left_led_strip}
|
||||||
|
tw="row-start-3 col-start-1"
|
||||||
|
onChange={(value) => onLedStripConfigChange('left_led_strip', value)}
|
||||||
|
/>
|
||||||
|
<LedStripEditor
|
||||||
|
config={config.right_led_strip}
|
||||||
|
tw="row-start-3 col-start-5"
|
||||||
|
onChange={(value) => onLedStripConfigChange('right_led_strip', value)}
|
||||||
|
/>
|
||||||
|
<LedStripEditor
|
||||||
|
config={config.bottom_led_strip}
|
||||||
|
tw="row-start-5 col-start-3"
|
||||||
|
onChange={(value) => onLedStripConfigChange('bottom_led_strip', value)}
|
||||||
|
/>
|
||||||
|
</StyledContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
57
src/configurator/components/led-strip-editor.tsx
Normal file
57
src/configurator/components/led-strip-editor.tsx
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { HTMLAttributes, useCallback } from 'react';
|
||||||
|
import { FC } from 'react';
|
||||||
|
import { LedStripConfig } from '../models/led-strip-config';
|
||||||
|
import tw, { css, styled, theme } from 'twin.macro';
|
||||||
|
import { faLeftRight, faMinus, faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
|
||||||
|
export interface LedStripEditorProps
|
||||||
|
extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {
|
||||||
|
config: LedStripConfig | null;
|
||||||
|
onChange?: (config: LedStripConfig | null) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const StyledContainer = styled.section(
|
||||||
|
tw`flex flex-wrap gap-2 self-start justify-self-start`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const StyledButton = styled.button(
|
||||||
|
tw`
|
||||||
|
bg-yellow-500 rounded-full h-4 w-4 text-xs shadow select-none`,
|
||||||
|
tw`hocus:scale-105 hocus:active:scale-95 active:bg-amber-600`,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const LedStripEditor: FC<LedStripEditorProps> = ({
|
||||||
|
config,
|
||||||
|
onChange,
|
||||||
|
...htmlAttrs
|
||||||
|
}) => {
|
||||||
|
const addLed = useCallback(() => {
|
||||||
|
if (config) {
|
||||||
|
onChange?.({ ...config, global_end_position: config.global_end_position + 1 });
|
||||||
|
} else {
|
||||||
|
onChange?.(new LedStripConfig(0, 0, 1));
|
||||||
|
}
|
||||||
|
}, [config, onChange]);
|
||||||
|
const removeLed = useCallback(() => {
|
||||||
|
if (!config) {
|
||||||
|
onChange?.(null);
|
||||||
|
} else {
|
||||||
|
onChange?.({ ...config, global_end_position: config.global_end_position - 1 });
|
||||||
|
}
|
||||||
|
}, [config, onChange]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledContainer {...htmlAttrs}>
|
||||||
|
<StyledButton title="Add LED" onClick={addLed}>
|
||||||
|
<FontAwesomeIcon icon={faPlus} />
|
||||||
|
</StyledButton>
|
||||||
|
<StyledButton title="Remove LED" onClick={removeLed}>
|
||||||
|
<FontAwesomeIcon icon={faMinus} />
|
||||||
|
</StyledButton>
|
||||||
|
<StyledButton title="Reverse">
|
||||||
|
<FontAwesomeIcon icon={faLeftRight} />
|
||||||
|
</StyledButton>
|
||||||
|
</StyledContainer>
|
||||||
|
);
|
||||||
|
};
|
@ -1,11 +1,36 @@
|
|||||||
import { HTMLAttributes } from 'react';
|
import { HTMLAttributes, useMemo } from 'react';
|
||||||
import { FC } from 'react';
|
import { FC } from 'react';
|
||||||
import { LedStripConfig } from '../models/led-strip-config';
|
import { LedStripConfig } from '../models/led-strip-config';
|
||||||
|
import tw, { css, styled, theme } from 'twin.macro';
|
||||||
|
import { splitEvery } from 'ramda';
|
||||||
|
|
||||||
export interface LedStripProps extends HTMLAttributes<HTMLElement> {
|
export interface LedStripProps extends HTMLAttributes<HTMLElement> {
|
||||||
config: LedStripConfig;
|
config: LedStripConfig | null;
|
||||||
|
colors: Uint8Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LedStrip: FC<LedStripProps> = ({ config, ...htmlAttrs }) => {
|
const StyledContainer = styled.section(
|
||||||
return <section {...htmlAttrs}>...</section>;
|
tw`dark:bg-transparent shadow-xl border-gray-500 border rounded-full flex flex-wrap justify-around items-center`,
|
||||||
|
css``,
|
||||||
|
);
|
||||||
|
|
||||||
|
const StyledPixel = styled.span(
|
||||||
|
({ rgb: [r, g, b] }: { rgb: [number, number, number] }) => [
|
||||||
|
tw`rounded-full h-3 w-3 bg-current block border border-gray-700`,
|
||||||
|
css`
|
||||||
|
color: rgb(${r}, ${g}, ${b});
|
||||||
|
`,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
export const LedStrip: FC<LedStripProps> = ({ config, colors, ...htmlAttrs }) => {
|
||||||
|
const pixels = useMemo(() => {
|
||||||
|
const pixels = splitEvery(3, Array.from(colors)) as Array<[number, number, number]>;
|
||||||
|
return pixels.map((rgb, index) => <StyledPixel key={index} rgb={rgb}></StyledPixel>);
|
||||||
|
}, [colors]);
|
||||||
|
return (
|
||||||
|
<StyledContainer {...htmlAttrs} css={[!config && tw`bg-gray-200`]}>
|
||||||
|
{pixels}
|
||||||
|
</StyledContainer>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,46 +1,96 @@
|
|||||||
import { invoke } from '@tauri-apps/api';
|
import { invoke } from '@tauri-apps/api';
|
||||||
import { FC, useMemo } from 'react';
|
import { FC, Fragment, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useAsync } from 'react-async-hook';
|
import tw from 'twin.macro';
|
||||||
|
import { useAsync, useAsyncCallback } from 'react-async-hook';
|
||||||
import { DisplayWithLedStrips } from './components/display-with-led-strips';
|
import { DisplayWithLedStrips } from './components/display-with-led-strips';
|
||||||
import { PickerConfiguration } from './models/picker-configuration';
|
import { PickerConfiguration } from './models/picker-configuration';
|
||||||
|
import { DisplayConfig } from './models/display-config';
|
||||||
|
import { ScreenshotDto } from './models/screenshot.dto';
|
||||||
|
import { Alert, Snackbar } from '@mui/material';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { update } from 'ramda';
|
||||||
|
|
||||||
const getPickerConfig = () => invoke<PickerConfiguration>('get_picker_config');
|
const getPickerConfig = () => invoke<PickerConfiguration>('get_picker_config');
|
||||||
const getScreenshotOfDisplays = () =>
|
const getScreenshotOfDisplays = () =>
|
||||||
invoke<string[]>('take_snapshot').then((items) =>
|
invoke<ScreenshotDto[]>('take_snapshot').then((items) => {
|
||||||
items?.map((it) => `data:image/webp;base64,${it}`),
|
console.log(items);
|
||||||
);
|
return items;
|
||||||
|
});
|
||||||
|
const getScreenshotByConfig = async (config: DisplayConfig) => {
|
||||||
|
return await invoke<ScreenshotDto>('get_screenshot_by_config', {
|
||||||
|
config,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const Configurator: FC = () => {
|
export const Configurator: FC = () => {
|
||||||
const { loading: pendingPickerConfig, result: pickerConfig } = useAsync(
|
const { loading: pendingPickerConfig, result: savedPickerConfig } = useAsync(
|
||||||
getPickerConfig,
|
getPickerConfig,
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const { loading: pendingScreenshotOfDisplays, result: screenshotOfDisplays } = useAsync(
|
const { loading: pendingScreenshotOfDisplays, result: defaultScreenshotOfDisplays } =
|
||||||
getScreenshotOfDisplays,
|
useAsync(getScreenshotOfDisplays, []);
|
||||||
[],
|
|
||||||
);
|
const [screenshotOfDisplays, setScreenshotOfDisplays] = useState<ScreenshotDto[]>([]);
|
||||||
|
|
||||||
|
const { loading: pendingGetLedColorsByConfig, execute: onPickerChange } =
|
||||||
|
useAsyncCallback(async (value: DisplayConfig) => {
|
||||||
|
console.log(value);
|
||||||
|
const screenshot = await getScreenshotByConfig(value);
|
||||||
|
setScreenshotOfDisplays((old) => {
|
||||||
|
const index = old.findIndex((it) => it.config.id === screenshot.config.id);
|
||||||
|
console.log({ old, n: update(index, screenshot, old) });
|
||||||
|
return update(index, screenshot, old);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('screenshot', screenshot);
|
||||||
|
});
|
||||||
|
|
||||||
|
const [displayConfigs, setDisplayConfigs] = useState<DisplayConfig[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const displayConfigs = savedPickerConfig?.display_configs;
|
||||||
|
if (displayConfigs) {
|
||||||
|
setDisplayConfigs(displayConfigs);
|
||||||
|
}
|
||||||
|
}, [savedPickerConfig]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (defaultScreenshotOfDisplays) {
|
||||||
|
setScreenshotOfDisplays(defaultScreenshotOfDisplays);
|
||||||
|
}
|
||||||
|
}, [defaultScreenshotOfDisplays]);
|
||||||
|
|
||||||
const displays = useMemo(() => {
|
const displays = useMemo(() => {
|
||||||
if (pickerConfig && screenshotOfDisplays) {
|
if (screenshotOfDisplays) {
|
||||||
|
console.log({ c: screenshotOfDisplays });
|
||||||
return screenshotOfDisplays.map((screenshot, index) => (
|
return screenshotOfDisplays.map((screenshot, index) => (
|
||||||
<DisplayWithLedStrips
|
<DisplayWithLedStrips
|
||||||
key={index}
|
key={index}
|
||||||
config={pickerConfig.display_configs[index] ?? {}}
|
config={screenshot.config}
|
||||||
screenshot={screenshot}
|
screenshot={screenshot}
|
||||||
|
onChange={(value) => onPickerChange(value)}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}, [pickerConfig, screenshotOfDisplays]);
|
}, [displayConfigs, screenshotOfDisplays]);
|
||||||
|
|
||||||
if (pendingPickerConfig || pendingScreenshotOfDisplays) {
|
if (pendingPickerConfig || pendingScreenshotOfDisplays) {
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
等待 {JSON.stringify({ pendingPickerConfig, pendingScreenshotOfDisplays })}
|
等待 {JSON.stringify({ pendingPickerConfig, pendingScreenshotOfDisplays })}
|
||||||
{displays}
|
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <section>{displays}</section>;
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<section>{displays}</section>;
|
||||||
|
<Snackbar open={pendingGetLedColorsByConfig} autoHideDuration={3000}>
|
||||||
|
<Alert icon={<FontAwesomeIcon icon={faSpinner} />} sx={{ width: '100%' }}>
|
||||||
|
This is a success message!
|
||||||
|
</Alert>
|
||||||
|
</Snackbar>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import { LedStripConfig } from './led-strip-config';
|
import { LedStripConfig } from './led-strip-config';
|
||||||
|
|
||||||
export class DisplayConfig {
|
export class DisplayConfig {
|
||||||
index_of_display!: number;
|
top_led_strip: LedStripConfig | null = null;
|
||||||
display_width!: number;
|
bottom_led_strip: LedStripConfig | null = null;
|
||||||
display_height!: number;
|
left_led_strip: LedStripConfig | null = null;
|
||||||
top_led_strip!: LedStripConfig;
|
right_led_strip: LedStripConfig | null = null;
|
||||||
bottom_led_strip!: LedStripConfig;
|
|
||||||
left_led_strip!: LedStripConfig;
|
constructor(
|
||||||
right_led_strip!: LedStripConfig;
|
public id: number,
|
||||||
|
public index_of_display: number,
|
||||||
|
public display_width: number,
|
||||||
|
public display_height: number,
|
||||||
|
) {}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
export class LedStripConfig {
|
export class LedStripConfig {
|
||||||
index!: number;
|
constructor(
|
||||||
global_start_position!: number;
|
public index: number,
|
||||||
global_end_position!: number;
|
public global_start_position: number,
|
||||||
|
public global_end_position: number,
|
||||||
|
) {}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { DisplayConfig } from './display-config';
|
import { DisplayConfig } from './display-config';
|
||||||
|
|
||||||
export class PickerConfiguration {
|
export class PickerConfiguration {
|
||||||
config_version!: number;
|
constructor(
|
||||||
display_configs!: DisplayConfig[];
|
public display_configs: DisplayConfig[] = [],
|
||||||
|
public config_version: number = 1,
|
||||||
|
) {}
|
||||||
}
|
}
|
||||||
|
12
src/configurator/models/screenshot.dto.ts
Normal file
12
src/configurator/models/screenshot.dto.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { DisplayConfig } from './display-config';
|
||||||
|
|
||||||
|
export class ScreenshotDto {
|
||||||
|
encode_image!: string;
|
||||||
|
config!: DisplayConfig;
|
||||||
|
colors!: {
|
||||||
|
top: Uint8Array;
|
||||||
|
bottom: Uint8Array;
|
||||||
|
left: Uint8Array;
|
||||||
|
right: Uint8Array;
|
||||||
|
};
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from "react-dom/client";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
import "./style.css";
|
import GlobalStyles from './styles/global-styles';
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
|
<GlobalStyles />
|
||||||
<App />
|
<App />
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
);
|
);
|
@ -5,7 +5,8 @@ import tw, { theme, GlobalStyles as BaseStyles } from 'twin.macro';
|
|||||||
const customStyles = css({
|
const customStyles = css({
|
||||||
body: {
|
body: {
|
||||||
WebkitTapHighlightColor: theme`colors.purple.500`,
|
WebkitTapHighlightColor: theme`colors.purple.500`,
|
||||||
...tw`antialiased dark:bg-dark-800 bg-dark-100`,
|
...tw`antialiased`,
|
||||||
|
...tw`dark:bg-dark-800 bg-dark-100 dark:text-gray-100 text-gray-800`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: [
|
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
|
||||||
"./index.html",
|
|
||||||
"./src/**/*.{js,ts,jsx,tsx}",
|
|
||||||
],
|
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
|
colors: {
|
||||||
|
dark: {
|
||||||
|
800: '#0f0f0f',
|
||||||
|
100: '#f6f6f6',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user