style(code editor): improved UI / UX for code editor (#826)

* style(): improved code edito ui / ux

* fix(): fix build issue and use cn fn

* theme variable updated to tailwind neutral gray

* fix(): fix conflicts

* fix lint errors

---------

Co-authored-by: Jim Su <jimsu@protonmail.com>
This commit is contained in:
Akki
2024-04-08 18:32:45 +04:00
committed by GitHub
parent 6b7c5b09af
commit 6f795f5e9c
15 changed files with 429 additions and 299 deletions

View File

@@ -12,16 +12,10 @@
"@nextui-org/react": "^2.2.10",
"@react-types/shared": "^3.22.1",
"@reduxjs/toolkit": "^2.2.2",
"@testing-library/jest-dom": "^6.4.2",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@types/node": "^18.0.0 ",
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@types/react-syntax-highlighter": "^15.5.11",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@vitejs/plugin-react": "^4.2.1",
"@xterm/xterm": "^5.4.0",
"clsx": "^2.1.0",
"eslint-config-airbnb-typescript": "^18.0.0",
"framer-motion": "^11.0.24",
"i18next": "^23.10.1",
"i18next-browser-languagedetector": "^7.2.1",
@@ -2712,6 +2706,14 @@
"tailwind-variants": ">=0.1.13"
}
},
"node_modules/@nextui-org/system-rsc/node_modules/clsx": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
"engines": {
"node": ">=6"
}
},
"node_modules/@nextui-org/table": {
"version": "2.0.28",
"resolved": "https://registry.npmjs.org/@nextui-org/table/-/table-2.0.28.tgz",
@@ -3246,14 +3248,6 @@
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
}
},
"node_modules/@react-aria/focus/node_modules/clsx": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
"integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
"engines": {
"node": ">=6"
}
},
"node_modules/@react-aria/form": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@react-aria/form/-/form-3.0.3.tgz",
@@ -3643,14 +3637,6 @@
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
}
},
"node_modules/@react-aria/utils/node_modules/clsx": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
"integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
"engines": {
"node": ">=6"
}
},
"node_modules/@react-aria/visually-hidden": {
"version": "3.8.10",
"resolved": "https://registry.npmjs.org/@react-aria/visually-hidden/-/visually-hidden-3.8.10.tgz",
@@ -4211,9 +4197,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.0.tgz",
"integrity": "sha512-jwXtxYbRt1V+CdQSy6Z+uZti7JF5irRKF8hlKfEnF/xJpcNGuuiZMBvuoYM+x9sr9iWGnzrlM0+9hvQ1kgkf1w==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.1.tgz",
"integrity": "sha512-fH8/o8nSUek8ceQnT7K4EQbSiV7jgkHq81m9lWZFIXjJ7lJzpWXbQFpT/Zh6OZYnpFykvzC3fbEvEAFZu03dPA==",
"cpu": [
"arm"
],
@@ -4223,9 +4209,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.0.tgz",
"integrity": "sha512-fI9nduZhCccjzlsA/OuAwtFGWocxA4gqXGTLvOyiF8d+8o0fZUeSztixkYjcGq1fGZY3Tkq4yRvHPFxU+jdZ9Q==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.1.tgz",
"integrity": "sha512-Y/9OHLjzkunF+KGEoJr3heiD5X9OLa8sbT1lm0NYeKyaM3oMhhQFvPB0bNZYJwlq93j8Z6wSxh9+cyKQaxS7PQ==",
"cpu": [
"arm64"
],
@@ -4235,9 +4221,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.0.tgz",
"integrity": "sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.1.tgz",
"integrity": "sha512-+kecg3FY84WadgcuSVm6llrABOdQAEbNdnpi5X3UwWiFVhZIZvKgGrF7kmLguvxHNQy+UuRV66cLVl3S+Rkt+Q==",
"cpu": [
"arm64"
],
@@ -4247,9 +4233,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.0.tgz",
"integrity": "sha512-LDyFB9GRolGN7XI6955aFeI3wCdCUszFWumWU0deHA8VpR3nWRrjG6GtGjBrQxQKFevnUTHKCfPR4IvrW3kCgQ==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.1.tgz",
"integrity": "sha512-2pYRzEjVqq2TB/UNv47BV/8vQiXkFGVmPFwJb+1E0IFFZbIX8/jo1olxqqMbo6xCXf8kabANhp5bzCij2tFLUA==",
"cpu": [
"x64"
],
@@ -4259,9 +4245,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.0.tgz",
"integrity": "sha512-ygrGVhQP47mRh0AAD0zl6QqCbNsf0eTo+vgwkY6LunBcg0f2Jv365GXlDUECIyoXp1kKwL5WW6rsO429DBY/bA==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.1.tgz",
"integrity": "sha512-mS6wQ6Do6/wmrF9aTFVpIJ3/IDXhg1EZcQFYHZLHqw6AzMBjTHWnCG35HxSqUNphh0EHqSM6wRTT8HsL1C0x5g==",
"cpu": [
"arm"
],
@@ -4271,9 +4257,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.0.tgz",
"integrity": "sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.1.tgz",
"integrity": "sha512-p9rGKYkHdFMzhckOTFubfxgyIO1vw//7IIjBBRVzyZebWlzRLeNhqxuSaZ7kCEKVkm/kuC9fVRW9HkC/zNRG2w==",
"cpu": [
"arm64"
],
@@ -4283,9 +4269,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.0.tgz",
"integrity": "sha512-nrRw8ZTQKg6+Lttwqo6a2VxR9tOroa2m91XbdQ2sUUzHoedXlsyvY1fN4xWdqz8PKmf4orDwejxXHjh7YBGUCA==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.1.tgz",
"integrity": "sha512-nDY6Yz5xS/Y4M2i9JLQd3Rofh5OR8Bn8qe3Mv/qCVpHFlwtZSBYSPaU4mrGazWkXrdQ98GB//H0BirGR/SKFSw==",
"cpu": [
"arm64"
],
@@ -4295,9 +4281,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.0.tgz",
"integrity": "sha512-xV0d5jDb4aFu84XKr+lcUJ9y3qpIWhttO3Qev97z8DKLXR62LC3cXT/bMZXrjLF9X+P5oSmJTzAhqwUbY96PnA==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.1.tgz",
"integrity": "sha512-im7HE4VBL+aDswvcmfx88Mp1soqL9OBsdDBU8NqDEYtkri0qV0THhQsvZtZeNNlLeCUQ16PZyv7cqutjDF35qw==",
"cpu": [
"ppc64le"
],
@@ -4307,9 +4293,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.0.tgz",
"integrity": "sha512-SDDhBQwZX6LPRoPYjAZWyL27LbcBo7WdBFWJi5PI9RPCzU8ijzkQn7tt8NXiXRiFMJCVpkuMkBf4OxSxVMizAw==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.1.tgz",
"integrity": "sha512-RWdiHuAxWmzPJgaHJdpvUUlDz8sdQz4P2uv367T2JocdDa98iRw2UjIJ4QxSyt077mXZT2X6pKfT2iYtVEvOFw==",
"cpu": [
"riscv64"
],
@@ -4319,9 +4305,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.0.tgz",
"integrity": "sha512-RxB/qez8zIDshNJDufYlTT0ZTVut5eCpAZ3bdXDU9yTxBzui3KhbGjROK2OYTTor7alM7XBhssgoO3CZ0XD3qA==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.1.tgz",
"integrity": "sha512-VMgaGQ5zRX6ZqV/fas65/sUGc9cPmsntq2FiGmayW9KMNfWVG/j0BAqImvU4KTeOOgYSf1F+k6at1UfNONuNjA==",
"cpu": [
"s390x"
],
@@ -4331,9 +4317,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.0.tgz",
"integrity": "sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.1.tgz",
"integrity": "sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==",
"cpu": [
"x64"
],
@@ -4343,9 +4329,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.0.tgz",
"integrity": "sha512-i0QwbHYfnOMYsBEyjxcwGu5SMIi9sImDVjDg087hpzXqhBSosxkE7gyIYFHgfFl4mr7RrXksIBZ4DoLoP4FhJg==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.1.tgz",
"integrity": "sha512-JNEG/Ti55413SsreTguSx0LOVKX902OfXIKVg+TCXO6Gjans/k9O6ww9q3oLGjNDaTLxM+IHFMeXy/0RXL5R/g==",
"cpu": [
"x64"
],
@@ -4355,9 +4341,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.0.tgz",
"integrity": "sha512-Fq52EYb0riNHLBTAcL0cun+rRwyZ10S9vKzhGKKgeD+XbwunszSY0rVMco5KbOsTlwovP2rTOkiII/fQ4ih/zQ==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.1.tgz",
"integrity": "sha512-ryS22I9y0mumlLNwDFYZRDFLwWh3aKaC72CWjFcFvxK0U6v/mOkM5Up1bTbCRAhv3kEIwW2ajROegCIQViUCeA==",
"cpu": [
"arm64"
],
@@ -4367,9 +4353,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.0.tgz",
"integrity": "sha512-e/PBHxPdJ00O9p5Ui43+vixSgVf4NlLsmV6QneGERJ3lnjIua/kim6PRFe3iDueT1rQcgSkYP8ZBBXa/h4iPvw==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.1.tgz",
"integrity": "sha512-TdloItiGk+T0mTxKx7Hp279xy30LspMso+GzQvV2maYePMAWdmrzqSNZhUpPj3CGw12aGj57I026PgLCTu8CGg==",
"cpu": [
"ia32"
],
@@ -4379,9 +4365,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.0.tgz",
"integrity": "sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.1.tgz",
"integrity": "sha512-wQGI+LY/Py20zdUPq+XCem7JcPOyzIJBm3dli+56DJsQOHbnXZFEwgmnC6el1TPAfC8lBT3m+z69RmLykNUbew==",
"cpu": [
"x64"
],
@@ -5681,9 +5667,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001606",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001606.tgz",
"integrity": "sha512-LPbwnW4vfpJId225pwjZJOgX1m9sGfbw/RKJvw/t0QhYOOaTXHvkjVGFGPpvwEzufrjvTlsULnVTxdy4/6cqkg==",
"version": "1.0.30001607",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001607.tgz",
"integrity": "sha512-WcvhVRjXLKFB/kmOFVwELtMxyhq3iM/MvmXcyCe2PNf166c39mptscOc/45TTS96n2gpNV2z7+NakArTWZCQ3w==",
"funding": [
{
"type": "opencollective",
@@ -5904,9 +5890,9 @@
}
},
"node_modules/clsx": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz",
"integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==",
"engines": {
"node": ">=6"
}
@@ -9671,9 +9657,9 @@
}
},
"node_modules/jose": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/jose/-/jose-5.2.3.tgz",
"integrity": "sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA==",
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/jose/-/jose-5.2.4.tgz",
"integrity": "sha512-6ScbIk2WWCeXkmzF6bRPmEuaqy1m8SbsRFMa/FLrSCkGIhj8OLVG/IH+XHVmNMx/KUo8cVWEE6oKR4dJ+S0Rkg==",
"funding": {
"url": "https://github.com/sponsors/panva"
}
@@ -11721,9 +11707,9 @@
}
},
"node_modules/rollup": {
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.0.tgz",
"integrity": "sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ==",
"version": "4.14.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.14.1.tgz",
"integrity": "sha512-4LnHSdd3QK2pa1J6dFbfm1HN0D7vSK/ZuZTsdyUAlA6Rr1yTouUTL13HaDOGJVgby461AhrNGBS7sCGXXtT+SA==",
"dependencies": {
"@types/estree": "1.0.5"
},
@@ -11735,21 +11721,21 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.14.0",
"@rollup/rollup-android-arm64": "4.14.0",
"@rollup/rollup-darwin-arm64": "4.14.0",
"@rollup/rollup-darwin-x64": "4.14.0",
"@rollup/rollup-linux-arm-gnueabihf": "4.14.0",
"@rollup/rollup-linux-arm64-gnu": "4.14.0",
"@rollup/rollup-linux-arm64-musl": "4.14.0",
"@rollup/rollup-linux-powerpc64le-gnu": "4.14.0",
"@rollup/rollup-linux-riscv64-gnu": "4.14.0",
"@rollup/rollup-linux-s390x-gnu": "4.14.0",
"@rollup/rollup-linux-x64-gnu": "4.14.0",
"@rollup/rollup-linux-x64-musl": "4.14.0",
"@rollup/rollup-win32-arm64-msvc": "4.14.0",
"@rollup/rollup-win32-ia32-msvc": "4.14.0",
"@rollup/rollup-win32-x64-msvc": "4.14.0",
"@rollup/rollup-android-arm-eabi": "4.14.1",
"@rollup/rollup-android-arm64": "4.14.1",
"@rollup/rollup-darwin-arm64": "4.14.1",
"@rollup/rollup-darwin-x64": "4.14.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.14.1",
"@rollup/rollup-linux-arm64-gnu": "4.14.1",
"@rollup/rollup-linux-arm64-musl": "4.14.1",
"@rollup/rollup-linux-powerpc64le-gnu": "4.14.1",
"@rollup/rollup-linux-riscv64-gnu": "4.14.1",
"@rollup/rollup-linux-s390x-gnu": "4.14.1",
"@rollup/rollup-linux-x64-gnu": "4.14.1",
"@rollup/rollup-linux-x64-musl": "4.14.1",
"@rollup/rollup-win32-arm64-msvc": "4.14.1",
"@rollup/rollup-win32-ia32-msvc": "4.14.1",
"@rollup/rollup-win32-x64-msvc": "4.14.1",
"fsevents": "~2.3.2"
}
},

View File

@@ -13,17 +13,19 @@
"@reduxjs/toolkit": "^2.2.2",
"@vitejs/plugin-react": "^4.2.1",
"@xterm/xterm": "^5.4.0",
"clsx": "^2.1.0",
"eslint-config-airbnb-typescript": "^18.0.0",
"framer-motion": "^11.0.24",
"jose": "^5.2.3",
"i18next": "^23.10.1",
"i18next-browser-languagedetector": "^7.2.1",
"i18next-http-backend": "^2.5.0",
"jose": "^5.2.3",
"monaco-editor": "^0.47.0",
"react": "^18.2.0",
"react-accessible-treeview": "^2.8.3",
"react-dom": "^18.2.0",
"react-icons": "^5.0.1",
"react-i18next": "^14.1.0",
"react-icons": "^5.0.1",
"react-redux": "^9.1.0",
"react-syntax-highlighter": "^15.5.0",
"tailwind-merge": "^2.2.2",

View File

@@ -19,7 +19,7 @@ interface Props {
function LeftNav({ setSettingOpen }: Props): JSX.Element {
return (
<div className="flex flex-col h-full p-4 bg-bg-dark w-16 items-center shrink-0">
<div className="flex flex-col h-full p-4 bg-neutral-900 w-16 items-center shrink-0">
<div
className="mt-auto cursor-pointer hover:opacity-80"
onClick={() => setSettingOpen(true)}
@@ -69,18 +69,18 @@ function App(): JSX.Element {
};
return (
<div className="flex h-screen bg-bg-dark text-white">
<div className="flex h-screen bg-neutral-900 text-white">
<LeftNav setSettingOpen={setSettingOpen} />
<div className="flex flex-col grow gap-3 py-3 pr-3">
<div className="flex gap-3 grow min-h-0">
<div className="w-[500px] shrink-0 rounded-xl overflow-hidden border border-border">
<div className="w-[500px] shrink-0 rounded-xl overflow-hidden border border-neutral-600">
<ChatInterface />
</div>
<div className="flex flex-col flex-1 overflow-hidden rounded-xl bg-bg-workspace border border-border">
<div className="flex flex-col flex-1 overflow-hidden rounded-xl bg-neutral-800 border border-neutral-600">
<Workspace />
</div>
</div>
<div className="h-72 shrink-0 bg-bg-workspace rounded-xl border border-border flex flex-col">
<div className="h-72 shrink-0 bg-neutral-800 rounded-xl border border-neutral-600 flex flex-col">
<Terminal key="terminal" />
</div>
</div>

View File

@@ -13,7 +13,7 @@ function Browser(): JSX.Element {
: `data:image/png;base64,${screenshotSrc || ""}`;
return (
<div className="h-full m-2 bg-bg-workspace mockup-browser">
<div className="h-full m-2 bg-neutral-700 mockup-browser">
<div className="mockup-browser-toolbar">
<div className="input">{url}</div>
</div>

View File

@@ -139,8 +139,8 @@ function ChatInterface(): JSX.Element {
const { initialized } = useSelector((state: RootState) => state.task);
return (
<div className="flex flex-col h-full p-0 bg-bg-workspace">
<div className="border-b border-border text-lg px-4 py-2">Chat</div>
<div className="flex flex-col h-full p-0 bg-neutral-800">
<div className="border-b border-neutral-600 text-sm px-4 py-2">Chat</div>
{initialized ? <MessageList /> : <InitializingStatus />}
<Input />
</div>

View File

@@ -1,166 +1,17 @@
import Editor, { Monaco } from "@monaco-editor/react";
import type { editor } from "monaco-editor";
import React, { useEffect, useState } from "react";
import TreeView, { flattenTree } from "react-accessible-treeview";
import { DiJavascript } from "react-icons/di";
import {
FaCss3,
FaFile,
FaFolder,
FaFolderOpen,
FaHtml5,
FaList,
FaMarkdown,
FaNpm,
FaPython,
} from "react-icons/fa";
import { VscClose, VscListTree, VscRefresh } from "react-icons/vsc";
import React, { useState } from "react";
import { Tabs, Tab } from "@nextui-org/react";
import { useSelector } from "react-redux";
import { getWorkspace, selectFile } from "../services/fileService";
import { setCode, updateWorkspace } from "../state/codeSlice";
import store, { RootState } from "../store";
interface FileIconProps {
filename: string;
}
function FileIcon({ filename }: FileIconProps): JSX.Element | null {
const extension = filename.slice(filename.lastIndexOf(".") + 1);
switch (extension) {
case "js":
return <DiJavascript />;
case "ts":
return <DiJavascript />;
case "py":
return <FaPython />;
case "css":
return <FaCss3 />;
case "json":
return <FaList />;
case "npmignore":
return <FaNpm />;
case "html":
return <FaHtml5 />;
case "md":
return <FaMarkdown />;
default:
return <FaFile />;
}
}
interface FolderIconProps {
isOpen: boolean;
}
function FolderIcon({ isOpen }: FolderIconProps): JSX.Element {
return isOpen ? (
<FaFolderOpen color="D9D3D0" className="icon" />
) : (
<FaFolder color="D9D3D0" className="icon" />
);
}
function Files(): JSX.Element | null {
const workspaceFolder = useSelector(
(state: RootState) => state.code.workspaceFolder,
);
const selectedIds = useSelector((state: RootState) => state.code.selectedIds);
const [explorerOpen, setExplorerOpen] = useState(true);
const workspaceTree = flattenTree(workspaceFolder);
useEffect(() => {
getWorkspace().then((file) => store.dispatch(updateWorkspace(file)));
}, []);
if (workspaceTree.length <= 1) {
return null;
}
if (!explorerOpen) {
return (
<div className="h-full bg-bg-workspace border-r-1 flex flex-col">
<div className="flex gap-1 border-b-1 p-1 justify-end">
<VscListTree
className="cursor-pointer"
onClick={() => setExplorerOpen(true)}
/>
</div>
</div>
);
}
return (
<div className="min-w-[250px] h-full bg-bg-workspace border-r-1 flex flex-col">
<div className="flex gap-1 border-b-1 p-1 justify-end">
<VscRefresh
onClick={() =>
getWorkspace().then((file) => store.dispatch(updateWorkspace(file)))
}
className="cursor-pointer"
/>
<VscClose
className="cursor-pointer"
onClick={() => setExplorerOpen(false)}
/>
</div>
<div className="w-full overflow-x-auto h-full py-2">
<TreeView
className="font-mono text-sm"
data={workspaceTree}
selectedIds={selectedIds}
expandedIds={workspaceTree.map((node) => node.id)}
onNodeSelect={(node) => {
if (!node.isBranch) {
let fullPath = node.element.name;
let currentNode = workspaceTree.find(
(file) => file.id === node.element.id,
);
while (currentNode !== undefined && currentNode.parent) {
currentNode = workspaceTree.find(
(file) => file.id === node.element.parent,
);
fullPath = `${currentNode!.name}/${fullPath}`;
}
selectFile(fullPath).then((code) => {
store.dispatch(setCode(code));
});
}
}}
// eslint-disable-next-line react/no-unstable-nested-components
nodeRenderer={({
element,
isBranch,
isExpanded,
getNodeProps,
level,
}) => (
<div
// eslint-disable-next-line react/jsx-props-no-spreading
{...getNodeProps()}
style={{ paddingLeft: 20 * (level - 1) }}
className="cursor-pointer nowrap flex items-center gap-2 aria-selected:bg-slate-500 hover:bg-slate-700"
>
<div className="shrink-0">
{isBranch ? (
<FolderIcon isOpen={isExpanded} />
) : (
<FileIcon filename={element.name} />
)}
</div>
{element.name}
</div>
)}
/>
</div>
</div>
);
}
import { RootState } from "../store";
import Files from "./Files";
import { cn } from "../utils/utils";
function CodeEditor(): JSX.Element {
const [selectedFileName, setSelectedFileName] = useState("welcome");
const [explorerOpen, setExplorerOpen] = useState(true);
const code = useSelector((state: RootState) => state.code.code);
const bgColor = getComputedStyle(document.documentElement)
.getPropertyValue("--bg-workspace")
.trim();
const handleEditorDidMount = (
editor: editor.IStandaloneCodeEditor,
monaco: Monaco,
@@ -171,7 +22,7 @@ function CodeEditor(): JSX.Element {
inherit: true,
rules: [],
colors: {
"editor.background": bgColor,
"editor.background": "#171717",
},
});
@@ -180,16 +31,50 @@ function CodeEditor(): JSX.Element {
};
return (
<div className="w-full h-full bg-bg-workspace flex">
<Files />
<Editor
height="95%"
theme="vs-dark"
defaultLanguage="python"
defaultValue="# Welcome to OpenDevin!"
value={code}
onMount={handleEditorDidMount}
/>
<div
className={`${cn(
explorerOpen ? "grid-cols-[250px_auto]" : "grid-cols-[50px_auto]",
)} grid h-full bg-neutral-900 transition-all duration-500 ease-in-out`}
>
<div>
<Files
setSelectedFileName={setSelectedFileName}
setExplorerOpen={setExplorerOpen}
explorerOpen={explorerOpen}
/>
</div>
<div>
<Tabs
disableCursorAnimation
classNames={{
tabList:
"w-full relative rounded-none bg-neutral-900 p-0 border-r border-divider",
cursor: "w-full bg-neutral-600 rounded-none",
tab: "max-w-fit px-4 h-[36px]",
tabContent: "group-data-[selected=true]:text-neutral-50 ",
}}
aria-label="Options"
>
<Tab
key={
selectedFileName === ""
? "Welcome"
: selectedFileName.toLocaleLowerCase()
}
title={!selectedFileName ? "Welcome" : selectedFileName}
>
<div>
<Editor
height="100vh"
defaultLanguage="python"
defaultValue="# Welcome to OpenDevin!"
value={code}
onMount={handleEditorDidMount}
/>
</div>
</Tab>
</Tabs>
</div>
</div>
);
}

View File

@@ -0,0 +1,41 @@
import React from "react";
import { DiJavascript } from "react-icons/di";
import {
FaCss3,
FaFile,
FaHtml5,
FaList,
FaMarkdown,
FaNpm,
FaPython,
} from "react-icons/fa";
interface FileIconProps {
filename: string;
}
function FileIcon({ filename }: FileIconProps): JSX.Element | null {
const extension = filename.slice(filename.lastIndexOf(".") + 1);
switch (extension) {
case "js":
return <DiJavascript />;
case "ts":
return <DiJavascript />;
case "py":
return <FaPython />;
case "css":
return <FaCss3 />;
case "json":
return <FaList />;
case "npmignore":
return <FaNpm />;
case "html":
return <FaHtml5 />;
case "md":
return <FaMarkdown />;
default:
return <FaFile />;
}
}
export default FileIcon;

View File

@@ -0,0 +1,175 @@
import React, { useEffect } from "react";
import TreeView, { flattenTree } from "react-accessible-treeview";
import { AiOutlineFolder } from "react-icons/ai";
import { Accordion, AccordionItem, Button } from "@nextui-org/react";
import {
TbLayoutSidebarLeftCollapseFilled,
TbLayoutSidebarRightCollapseFilled,
} from "react-icons/tb";
import { IoIosArrowDown } from "react-icons/io";
import { VscRefresh } from "react-icons/vsc";
import { useSelector } from "react-redux";
import { getWorkspace, selectFile } from "../services/fileService";
import { setCode, updateWorkspace } from "../state/codeSlice";
import store, { RootState } from "../store";
import FolderIcon from "./FolderIcon";
import FileIcon from "./FileIcons";
interface FilesProps {
setSelectedFileName: React.Dispatch<React.SetStateAction<string>>;
setExplorerOpen: React.Dispatch<React.SetStateAction<boolean>>;
explorerOpen: boolean;
}
function Files({
setSelectedFileName,
setExplorerOpen,
explorerOpen,
}: FilesProps): JSX.Element {
const workspaceFolder = useSelector(
(state: RootState) => state.code.workspaceFolder,
);
const selectedIds = useSelector((state: RootState) => state.code.selectedIds);
const workspaceTree = flattenTree(workspaceFolder);
useEffect(() => {
getWorkspace().then((file) => store.dispatch(updateWorkspace(file)));
}, []);
if (workspaceTree.length <= 1) {
<div className="h-full bg-neutral-700 border-neutral-600 items-center border-r-1 flex flex-col">
<div>No workspace found</div>
</div>;
}
if (!explorerOpen) {
return (
<div className="h-full bg-neutral-800 border-neutral-600 items-center border-r-1 flex flex-col">
<div className="flex mt-2 p-1 justify-end">
<TbLayoutSidebarRightCollapseFilled
className="cursor-pointer"
onClick={() => setExplorerOpen(true)}
/>
</div>
</div>
);
}
return (
<div className="bg-neutral-800 h-full border-r-1 border-r-neutral-600 flex flex-col">
<div className="flex p-2 items-center justify-between ">
<Accordion className="px-0" defaultExpandedKeys={["1"]} isCompact>
<AccordionItem
classNames={{
title: "editor-accordion-title",
content: "editor-accordion-content",
}}
hideIndicator
key="1"
aria-label={workspaceFolder.name}
title={
<div className="group flex items-center justify-between ">
<span className="text-neutral-400">{workspaceFolder.name}</span>
<div className="opacity-0 translate-y-[10px] transition-all ease-in-out group-hover:opacity-100 transform group-hover:-translate-y-0 ">
<Button
type="button"
style={{
width: "24px",
height: "24px",
}}
variant="flat"
onClick={() =>
getWorkspace().then((file) =>
store.dispatch(updateWorkspace(file)),
)
}
className="cursor-pointer text-[12px] bg-neutral-800"
isIconOnly
aria-label="Refresh"
>
<VscRefresh />
</Button>
<Button
type="button"
style={{
width: "24px",
height: "24px",
}}
variant="flat"
onClick={() => setExplorerOpen(false)}
className="cursor-pointer text-[12px] bg-neutral-800"
isIconOnly
aria-label="Refresh"
>
<TbLayoutSidebarLeftCollapseFilled />
</Button>
</div>
</div>
}
className="editor-accordion"
startContent={
<div className="flex items-center gap-1">
<IoIosArrowDown className="text-neutral-400" />
<AiOutlineFolder className="text-neutral-400" />
</div>
}
>
<div className="w-full overflow-x-auto h-full py-2">
<TreeView
className="font-mono text-sm text-neutral-400"
data={workspaceTree}
selectedIds={selectedIds}
expandedIds={workspaceTree.map((node) => node.id)}
onNodeSelect={(node) => {
if (!node.isBranch) {
let fullPath = node.element.name;
setSelectedFileName(fullPath);
let currentNode = workspaceTree.find(
(file) => file.id === node.element.id,
);
while (currentNode !== undefined && currentNode.parent) {
currentNode = workspaceTree.find(
(file) => file.id === node.element.parent,
);
fullPath = `${currentNode!.name}/${fullPath}`;
}
selectFile(fullPath).then((code) => {
store.dispatch(setCode(code));
});
}
}}
// eslint-disable-next-line react/no-unstable-nested-components
nodeRenderer={({
element,
isBranch,
isExpanded,
getNodeProps,
level,
}) => (
<div
// eslint-disable-next-line react/jsx-props-no-spreading
{...getNodeProps()}
style={{ paddingLeft: 20 * (level - 1) }}
className="cursor-pointer rounded-[5px] p-1 nowrap flex items-center gap-2 aria-selected:bg-neutral-600 aria-selected:text-neutral-50 hover:text-neutral-50"
>
<div className="shrink-0 pl-5">
{isBranch ? (
<FolderIcon isOpen={isExpanded} />
) : (
<FileIcon filename={element.name} />
)}
</div>
{element.name}
</div>
)}
/>
</div>
</AccordionItem>
</Accordion>
</div>
</div>
);
}
export default Files;

View File

@@ -0,0 +1,16 @@
import React from "react";
import { FaFolder, FaFolderOpen } from "react-icons/fa";
interface FolderIconProps {
isOpen: boolean;
}
function FolderIcon({ isOpen }: FolderIconProps): JSX.Element {
return isOpen ? (
<FaFolderOpen color="D9D3D0" className="icon" />
) : (
<FaFolder color="D9D3D0" className="icon" />
);
}
export default FolderIcon;

View File

@@ -1,7 +1,7 @@
import React from "react";
function Planner(): JSX.Element {
return <div className="h-full w-full bg-bg-workspace">Coming soon...</div>;
return <div className="h-full w-full bg-neutral-700">Coming soon...</div>;
}
export default Planner;

View File

@@ -52,10 +52,6 @@ function Terminal(): JSX.Element {
const { commands } = useSelector((state: RootState) => state.cmd);
useEffect(() => {
const bgColor = getComputedStyle(document.documentElement)
.getPropertyValue("--bg-workspace")
.trim();
const terminal = new XtermTerminal({
// This value is set to the appropriate value by the
// `fitAddon.fit()` call below.
@@ -66,7 +62,7 @@ function Terminal(): JSX.Element {
fontFamily: "Menlo, Monaco, 'Courier New', monospace",
fontSize: 14,
theme: {
background: bgColor,
background: "#262626",
},
});
terminal.write("$ ");
@@ -104,7 +100,9 @@ function Terminal(): JSX.Element {
return (
<div className="flex flex-col h-full">
<div className="px-4 py-2 text-lg border-b border-border">Terminal</div>
<div className="px-4 py-2 text-sm border-b border-neutral-600">
Terminal
</div>
<div className="grow p-2 flex min-h-0">
<div ref={terminalRef} className="h-full w-full" />
</div>

View File

@@ -1,9 +1,9 @@
import { Tab, Tabs } from "@nextui-org/react";
import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { FaCode } from "react-icons/fa6";
import { IoIosGlobe } from "react-icons/io";
import Calendar from "../assets/calendar";
import Earth from "../assets/earth";
import Pencil from "../assets/pencil";
import { I18nKey } from "../i18n/declaration";
import { AllTabs, TabOption, TabType } from "../types/TabOption";
import Browser from "./Browser";
@@ -23,12 +23,12 @@ function Workspace() {
},
[TabOption.CODE]: {
name: t(I18nKey.WORKSPACE$CODE_EDITOR_TAB_LABEL),
icon: <Pencil />,
icon: <FaCode size={18} />,
component: <CodeEditor key="code" />,
},
[TabOption.BROWSER]: {
name: t(I18nKey.WORKSPACE$BROWSER_TAB_LABEL),
icon: <Earth />,
icon: <IoIosGlobe size={18} />,
component: <Browser key="browser" />,
},
}),
@@ -39,9 +39,17 @@ function Workspace() {
<>
<div
role="tablist"
className="tabs tabs-bordered tabs-lg border-b border-border"
className="tabs tabs-bordered tabs-lg border-b border-neutral-600"
>
<Tabs
disableCursorAnimation
classNames={{
tabList:
"w-full relative rounded-none bg-neutral-800 p-0 border-divider gap-0 h-[36px]",
cursor: "w-full bg-neutral-800 rounded-none",
tab: " rounded-none border-neutral-600 border-r-[1px] border-r",
tabContent: "group-data-[selected=true]:text-neutral-50",
}}
variant="light"
size="lg"
onSelectionChange={(v) => {
@@ -52,7 +60,7 @@ function Workspace() {
<Tab
key={tab}
title={
<div className="flex items-center space-x-2">
<div className="flex items-center space-x-2 justify-center text-xs">
{tabData[tab].icon}
<span>{tabData[tab].name}</span>
</div>
@@ -63,7 +71,7 @@ function Workspace() {
</div>
{Object.keys(tabData).map((tab) => (
<div
className="h-full w-full p-4 bg-bg-workspace"
className="h-full w-full bg-neutral-800"
key={tab}
hidden={activeTab !== tab}
>

View File

@@ -4,7 +4,12 @@
--bg-input: #393939;
--bg-workspace: #1f2228;
--border: #3c3c4a;
background-color: var(--bg-dark) !important;
--text-editor-base: #9099AC;
--text-editor-active:#C4CBDA;
--bg-editor-sidebar: #24272E;
--bg-editor-active: #31343D;
--border-editor-sidebar: #3C3C4A;
background-color: var(--neutral-900) !important;
}
body {
@@ -20,3 +25,22 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}
.editor-accordion h2 > button{
padding: 0;
}
.editor-accordion-title {
color: var(--bg-neutral-400) !important;
}
.editor-accordion-content {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
.editor-accordion-content ul {
display: flex;
flex-direction: column;
justify-content: center;
}

View File

@@ -0,0 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

View File

@@ -5,17 +5,6 @@ export default {
"./src/**/*.{js,ts,jsx,tsx}",
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
"bg-dark": "var(--bg-dark)",
"bg-light": "var(--bg-light)",
"bg-input": "var(--bg-input)",
"bg-workspace": "var(--bg-workspace)",
border: "var(--border)",
},
},
},
darkMode: "class",
plugins: [
nextui({