Spaces:
Running
Running
Commit ·
f5a3d5a
1
Parent(s): 5e0cacf
commit changes on 06 08 2025 001
Browse files- package-lock.json +174 -40
- package.json +3 -0
- src/FileUploadForm.js +263 -101
- src/prism-setup.js +32 -0
- src/utils/languageDetect.js +48 -0
package-lock.json
CHANGED
|
@@ -10,13 +10,16 @@
|
|
| 10 |
"dependencies": {
|
| 11 |
"@emotion/styled": "^11.14.1",
|
| 12 |
"@mui/icons-material": "^7.2.0",
|
|
|
|
| 13 |
"@mui/material": "^7.2.0",
|
|
|
|
| 14 |
"@testing-library/dom": "^10.4.0",
|
| 15 |
"@testing-library/jest-dom": "^6.6.3",
|
| 16 |
"@testing-library/react": "^16.3.0",
|
| 17 |
"@testing-library/user-event": "^13.5.0",
|
| 18 |
"axios": "^1.11.0",
|
| 19 |
"jszip": "^3.10.1",
|
|
|
|
| 20 |
"react": "^19.1.0",
|
| 21 |
"react-dom": "^19.1.0",
|
| 22 |
"react-scripts": "5.0.1",
|
|
@@ -3119,9 +3122,9 @@
|
|
| 3119 |
"license": "MIT"
|
| 3120 |
},
|
| 3121 |
"node_modules/@mui/core-downloads-tracker": {
|
| 3122 |
-
"version": "7.
|
| 3123 |
-
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.
|
| 3124 |
-
"integrity": "sha512-
|
| 3125 |
"license": "MIT",
|
| 3126 |
"funding": {
|
| 3127 |
"type": "opencollective",
|
|
@@ -3154,23 +3157,67 @@
|
|
| 3154 |
}
|
| 3155 |
}
|
| 3156 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3157 |
"node_modules/@mui/material": {
|
| 3158 |
-
"version": "7.
|
| 3159 |
-
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.
|
| 3160 |
-
"integrity": "sha512-
|
| 3161 |
"license": "MIT",
|
| 3162 |
"dependencies": {
|
| 3163 |
-
"@babel/runtime": "^7.
|
| 3164 |
-
"@mui/core-downloads-tracker": "^7.
|
| 3165 |
-
"@mui/system": "^7.
|
| 3166 |
-
"@mui/types": "^7.4.
|
| 3167 |
-
"@mui/utils": "^7.
|
| 3168 |
"@popperjs/core": "^2.11.8",
|
| 3169 |
"@types/react-transition-group": "^4.4.12",
|
| 3170 |
"clsx": "^2.1.1",
|
| 3171 |
"csstype": "^3.1.3",
|
| 3172 |
"prop-types": "^15.8.1",
|
| 3173 |
-
"react-is": "^19.1.
|
| 3174 |
"react-transition-group": "^4.4.5"
|
| 3175 |
},
|
| 3176 |
"engines": {
|
|
@@ -3183,7 +3230,7 @@
|
|
| 3183 |
"peerDependencies": {
|
| 3184 |
"@emotion/react": "^11.5.0",
|
| 3185 |
"@emotion/styled": "^11.3.0",
|
| 3186 |
-
"@mui/material-pigment-css": "^7.
|
| 3187 |
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
| 3188 |
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
| 3189 |
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
@@ -3210,13 +3257,13 @@
|
|
| 3210 |
"license": "MIT"
|
| 3211 |
},
|
| 3212 |
"node_modules/@mui/private-theming": {
|
| 3213 |
-
"version": "7.
|
| 3214 |
-
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.
|
| 3215 |
-
"integrity": "sha512-
|
| 3216 |
"license": "MIT",
|
| 3217 |
"dependencies": {
|
| 3218 |
-
"@babel/runtime": "^7.
|
| 3219 |
-
"@mui/utils": "^7.
|
| 3220 |
"prop-types": "^15.8.1"
|
| 3221 |
},
|
| 3222 |
"engines": {
|
|
@@ -3237,12 +3284,12 @@
|
|
| 3237 |
}
|
| 3238 |
},
|
| 3239 |
"node_modules/@mui/styled-engine": {
|
| 3240 |
-
"version": "7.
|
| 3241 |
-
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.
|
| 3242 |
-
"integrity": "sha512-
|
| 3243 |
"license": "MIT",
|
| 3244 |
"dependencies": {
|
| 3245 |
-
"@babel/runtime": "^7.
|
| 3246 |
"@emotion/cache": "^11.14.0",
|
| 3247 |
"@emotion/serialize": "^1.3.3",
|
| 3248 |
"@emotion/sheet": "^1.4.0",
|
|
@@ -3271,16 +3318,16 @@
|
|
| 3271 |
}
|
| 3272 |
},
|
| 3273 |
"node_modules/@mui/system": {
|
| 3274 |
-
"version": "7.
|
| 3275 |
-
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.
|
| 3276 |
-
"integrity": "sha512-
|
| 3277 |
"license": "MIT",
|
| 3278 |
"dependencies": {
|
| 3279 |
-
"@babel/runtime": "^7.
|
| 3280 |
-
"@mui/private-theming": "^7.
|
| 3281 |
-
"@mui/styled-engine": "^7.
|
| 3282 |
-
"@mui/types": "^7.4.
|
| 3283 |
-
"@mui/utils": "^7.
|
| 3284 |
"clsx": "^2.1.1",
|
| 3285 |
"csstype": "^3.1.3",
|
| 3286 |
"prop-types": "^15.8.1"
|
|
@@ -3311,12 +3358,12 @@
|
|
| 3311 |
}
|
| 3312 |
},
|
| 3313 |
"node_modules/@mui/types": {
|
| 3314 |
-
"version": "7.4.
|
| 3315 |
-
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.
|
| 3316 |
-
"integrity": "sha512-
|
| 3317 |
"license": "MIT",
|
| 3318 |
"dependencies": {
|
| 3319 |
-
"@babel/runtime": "^7.
|
| 3320 |
},
|
| 3321 |
"peerDependencies": {
|
| 3322 |
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
@@ -3328,17 +3375,17 @@
|
|
| 3328 |
}
|
| 3329 |
},
|
| 3330 |
"node_modules/@mui/utils": {
|
| 3331 |
-
"version": "7.
|
| 3332 |
-
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.
|
| 3333 |
-
"integrity": "sha512-
|
| 3334 |
"license": "MIT",
|
| 3335 |
"dependencies": {
|
| 3336 |
-
"@babel/runtime": "^7.
|
| 3337 |
-
"@mui/types": "^7.4.
|
| 3338 |
"@types/prop-types": "^15.7.15",
|
| 3339 |
"clsx": "^2.1.1",
|
| 3340 |
"prop-types": "^15.8.1",
|
| 3341 |
-
"react-is": "^19.1.
|
| 3342 |
},
|
| 3343 |
"engines": {
|
| 3344 |
"node": ">=14.0.0"
|
|
@@ -3363,6 +3410,69 @@
|
|
| 3363 |
"integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==",
|
| 3364 |
"license": "MIT"
|
| 3365 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3366 |
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
|
| 3367 |
"version": "5.1.1-v1",
|
| 3368 |
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
|
|
@@ -14133,6 +14243,15 @@
|
|
| 14133 |
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
|
| 14134 |
}
|
| 14135 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14136 |
"node_modules/process-nextick-args": {
|
| 14137 |
"version": "2.0.1",
|
| 14138 |
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
|
@@ -14811,6 +14930,12 @@
|
|
| 14811 |
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
| 14812 |
"license": "MIT"
|
| 14813 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14814 |
"node_modules/resolve": {
|
| 14815 |
"version": "1.22.10",
|
| 14816 |
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
|
@@ -17130,6 +17255,15 @@
|
|
| 17130 |
"requires-port": "^1.0.0"
|
| 17131 |
}
|
| 17132 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17133 |
"node_modules/util-deprecate": {
|
| 17134 |
"version": "1.0.2",
|
| 17135 |
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
|
|
|
| 10 |
"dependencies": {
|
| 11 |
"@emotion/styled": "^11.14.1",
|
| 12 |
"@mui/icons-material": "^7.2.0",
|
| 13 |
+
"@mui/lab": "^7.0.0-beta.15",
|
| 14 |
"@mui/material": "^7.2.0",
|
| 15 |
+
"@mui/x-tree-view": "^8.9.2",
|
| 16 |
"@testing-library/dom": "^10.4.0",
|
| 17 |
"@testing-library/jest-dom": "^6.6.3",
|
| 18 |
"@testing-library/react": "^16.3.0",
|
| 19 |
"@testing-library/user-event": "^13.5.0",
|
| 20 |
"axios": "^1.11.0",
|
| 21 |
"jszip": "^3.10.1",
|
| 22 |
+
"prismjs": "^1.30.0",
|
| 23 |
"react": "^19.1.0",
|
| 24 |
"react-dom": "^19.1.0",
|
| 25 |
"react-scripts": "5.0.1",
|
|
|
|
| 3122 |
"license": "MIT"
|
| 3123 |
},
|
| 3124 |
"node_modules/@mui/core-downloads-tracker": {
|
| 3125 |
+
"version": "7.3.0",
|
| 3126 |
+
"resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.0.tgz",
|
| 3127 |
+
"integrity": "sha512-E4eWI90atwCf0rUjuzdlDRI6coA03ZEOAqk5qjEU9IdCLYRlOG65P7WBCpwFYOwDqzUVCHzx8U4q//csULLsOg==",
|
| 3128 |
"license": "MIT",
|
| 3129 |
"funding": {
|
| 3130 |
"type": "opencollective",
|
|
|
|
| 3157 |
}
|
| 3158 |
}
|
| 3159 |
},
|
| 3160 |
+
"node_modules/@mui/lab": {
|
| 3161 |
+
"version": "7.0.0-beta.15",
|
| 3162 |
+
"resolved": "https://registry.npmjs.org/@mui/lab/-/lab-7.0.0-beta.15.tgz",
|
| 3163 |
+
"integrity": "sha512-Paun0L+WrW2gcNI1x9+jSzO+fnV7qvMwBkMX47wkSBPPynhwLoWsK25C/xWUdmGsipApkdWak4c8HhNlqziYOw==",
|
| 3164 |
+
"license": "MIT",
|
| 3165 |
+
"dependencies": {
|
| 3166 |
+
"@babel/runtime": "^7.28.2",
|
| 3167 |
+
"@mui/system": "^7.3.0",
|
| 3168 |
+
"@mui/types": "^7.4.5",
|
| 3169 |
+
"@mui/utils": "^7.3.0",
|
| 3170 |
+
"clsx": "^2.1.1",
|
| 3171 |
+
"prop-types": "^15.8.1"
|
| 3172 |
+
},
|
| 3173 |
+
"engines": {
|
| 3174 |
+
"node": ">=14.0.0"
|
| 3175 |
+
},
|
| 3176 |
+
"funding": {
|
| 3177 |
+
"type": "opencollective",
|
| 3178 |
+
"url": "https://opencollective.com/mui-org"
|
| 3179 |
+
},
|
| 3180 |
+
"peerDependencies": {
|
| 3181 |
+
"@emotion/react": "^11.5.0",
|
| 3182 |
+
"@emotion/styled": "^11.3.0",
|
| 3183 |
+
"@mui/material": "^7.3.0",
|
| 3184 |
+
"@mui/material-pigment-css": "^7.3.0",
|
| 3185 |
+
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
| 3186 |
+
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
| 3187 |
+
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
| 3188 |
+
},
|
| 3189 |
+
"peerDependenciesMeta": {
|
| 3190 |
+
"@emotion/react": {
|
| 3191 |
+
"optional": true
|
| 3192 |
+
},
|
| 3193 |
+
"@emotion/styled": {
|
| 3194 |
+
"optional": true
|
| 3195 |
+
},
|
| 3196 |
+
"@mui/material-pigment-css": {
|
| 3197 |
+
"optional": true
|
| 3198 |
+
},
|
| 3199 |
+
"@types/react": {
|
| 3200 |
+
"optional": true
|
| 3201 |
+
}
|
| 3202 |
+
}
|
| 3203 |
+
},
|
| 3204 |
"node_modules/@mui/material": {
|
| 3205 |
+
"version": "7.3.0",
|
| 3206 |
+
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.0.tgz",
|
| 3207 |
+
"integrity": "sha512-t0fb7+zEDTjnVe4hqzNvoGIopzGJ6AyN+qodGRENAFvL/UV3IT/vFIMHloFGnJ9DPmIgWaWasKgefPUU3OsgOQ==",
|
| 3208 |
"license": "MIT",
|
| 3209 |
"dependencies": {
|
| 3210 |
+
"@babel/runtime": "^7.28.2",
|
| 3211 |
+
"@mui/core-downloads-tracker": "^7.3.0",
|
| 3212 |
+
"@mui/system": "^7.3.0",
|
| 3213 |
+
"@mui/types": "^7.4.5",
|
| 3214 |
+
"@mui/utils": "^7.3.0",
|
| 3215 |
"@popperjs/core": "^2.11.8",
|
| 3216 |
"@types/react-transition-group": "^4.4.12",
|
| 3217 |
"clsx": "^2.1.1",
|
| 3218 |
"csstype": "^3.1.3",
|
| 3219 |
"prop-types": "^15.8.1",
|
| 3220 |
+
"react-is": "^19.1.1",
|
| 3221 |
"react-transition-group": "^4.4.5"
|
| 3222 |
},
|
| 3223 |
"engines": {
|
|
|
|
| 3230 |
"peerDependencies": {
|
| 3231 |
"@emotion/react": "^11.5.0",
|
| 3232 |
"@emotion/styled": "^11.3.0",
|
| 3233 |
+
"@mui/material-pigment-css": "^7.3.0",
|
| 3234 |
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
| 3235 |
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
| 3236 |
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
|
|
| 3257 |
"license": "MIT"
|
| 3258 |
},
|
| 3259 |
"node_modules/@mui/private-theming": {
|
| 3260 |
+
"version": "7.3.0",
|
| 3261 |
+
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.0.tgz",
|
| 3262 |
+
"integrity": "sha512-qU6rkH377L9byQrgXVW4rGsXVs7Q7H65Rj4IaITK3Vj2J5IP9nomMxJ77/w5kbJcEcaDEoLK42Ro3qMtHmvd4Q==",
|
| 3263 |
"license": "MIT",
|
| 3264 |
"dependencies": {
|
| 3265 |
+
"@babel/runtime": "^7.28.2",
|
| 3266 |
+
"@mui/utils": "^7.3.0",
|
| 3267 |
"prop-types": "^15.8.1"
|
| 3268 |
},
|
| 3269 |
"engines": {
|
|
|
|
| 3284 |
}
|
| 3285 |
},
|
| 3286 |
"node_modules/@mui/styled-engine": {
|
| 3287 |
+
"version": "7.3.0",
|
| 3288 |
+
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.0.tgz",
|
| 3289 |
+
"integrity": "sha512-O8GNVzpr+ZGzHXCGlYXnc9iSgBldrX3UtPswvLEZX8fyjKfh6wYVvbc7Oa6FdFKdbWWXAnrJ9YTVBQsk2VXDSg==",
|
| 3290 |
"license": "MIT",
|
| 3291 |
"dependencies": {
|
| 3292 |
+
"@babel/runtime": "^7.28.2",
|
| 3293 |
"@emotion/cache": "^11.14.0",
|
| 3294 |
"@emotion/serialize": "^1.3.3",
|
| 3295 |
"@emotion/sheet": "^1.4.0",
|
|
|
|
| 3318 |
}
|
| 3319 |
},
|
| 3320 |
"node_modules/@mui/system": {
|
| 3321 |
+
"version": "7.3.0",
|
| 3322 |
+
"resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.0.tgz",
|
| 3323 |
+
"integrity": "sha512-D4VclTIVbMxwrPeDF+PEfwCo9BC+4pYnM1OakA5iFznmE1QRVanyXtpUM3319IhlZolN82EG04iKk3XiiQZmHg==",
|
| 3324 |
"license": "MIT",
|
| 3325 |
"dependencies": {
|
| 3326 |
+
"@babel/runtime": "^7.28.2",
|
| 3327 |
+
"@mui/private-theming": "^7.3.0",
|
| 3328 |
+
"@mui/styled-engine": "^7.3.0",
|
| 3329 |
+
"@mui/types": "^7.4.5",
|
| 3330 |
+
"@mui/utils": "^7.3.0",
|
| 3331 |
"clsx": "^2.1.1",
|
| 3332 |
"csstype": "^3.1.3",
|
| 3333 |
"prop-types": "^15.8.1"
|
|
|
|
| 3358 |
}
|
| 3359 |
},
|
| 3360 |
"node_modules/@mui/types": {
|
| 3361 |
+
"version": "7.4.5",
|
| 3362 |
+
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.5.tgz",
|
| 3363 |
+
"integrity": "sha512-ZPwlAOE3e8C0piCKbaabwrqZbW4QvWz0uapVPWya7fYj6PeDkl5sSJmomT7wjOcZGPB48G/a6Ubidqreptxz4g==",
|
| 3364 |
"license": "MIT",
|
| 3365 |
"dependencies": {
|
| 3366 |
+
"@babel/runtime": "^7.28.2"
|
| 3367 |
},
|
| 3368 |
"peerDependencies": {
|
| 3369 |
"@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
|
|
|
| 3375 |
}
|
| 3376 |
},
|
| 3377 |
"node_modules/@mui/utils": {
|
| 3378 |
+
"version": "7.3.0",
|
| 3379 |
+
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.0.tgz",
|
| 3380 |
+
"integrity": "sha512-YdL6ebwFV7PIOidIsees3HxkZ8hZjj+/atKLuI1ENwvJJ1puiEoLEmuDU72qSbKu911/GeFa7pc7Cn/ZmAj6yQ==",
|
| 3381 |
"license": "MIT",
|
| 3382 |
"dependencies": {
|
| 3383 |
+
"@babel/runtime": "^7.28.2",
|
| 3384 |
+
"@mui/types": "^7.4.5",
|
| 3385 |
"@types/prop-types": "^15.7.15",
|
| 3386 |
"clsx": "^2.1.1",
|
| 3387 |
"prop-types": "^15.8.1",
|
| 3388 |
+
"react-is": "^19.1.1"
|
| 3389 |
},
|
| 3390 |
"engines": {
|
| 3391 |
"node": ">=14.0.0"
|
|
|
|
| 3410 |
"integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==",
|
| 3411 |
"license": "MIT"
|
| 3412 |
},
|
| 3413 |
+
"node_modules/@mui/x-internals": {
|
| 3414 |
+
"version": "8.9.2",
|
| 3415 |
+
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-8.9.2.tgz",
|
| 3416 |
+
"integrity": "sha512-qQl0sacWirbvQUdJOrUecsBQkI+vxI3/E1K/Wst6n/rb8ajelsGLMFLQ1PBig73xBT2vADmdcf3XerfH7TKPqQ==",
|
| 3417 |
+
"license": "MIT",
|
| 3418 |
+
"dependencies": {
|
| 3419 |
+
"@babel/runtime": "^7.28.2",
|
| 3420 |
+
"@mui/utils": "^7.2.0",
|
| 3421 |
+
"reselect": "^5.1.1",
|
| 3422 |
+
"use-sync-external-store": "^1.5.0"
|
| 3423 |
+
},
|
| 3424 |
+
"engines": {
|
| 3425 |
+
"node": ">=14.0.0"
|
| 3426 |
+
},
|
| 3427 |
+
"funding": {
|
| 3428 |
+
"type": "opencollective",
|
| 3429 |
+
"url": "https://opencollective.com/mui-org"
|
| 3430 |
+
},
|
| 3431 |
+
"peerDependencies": {
|
| 3432 |
+
"@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0",
|
| 3433 |
+
"react": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
| 3434 |
+
}
|
| 3435 |
+
},
|
| 3436 |
+
"node_modules/@mui/x-tree-view": {
|
| 3437 |
+
"version": "8.9.2",
|
| 3438 |
+
"resolved": "https://registry.npmjs.org/@mui/x-tree-view/-/x-tree-view-8.9.2.tgz",
|
| 3439 |
+
"integrity": "sha512-ExRRhLTwLodeUSUHV7VAkwKfIZmR1jJjv/iTvek3JA0ssyfGyzBVg6bjZtkny8QDRq+TGuvXmHhYTzc08BeZVg==",
|
| 3440 |
+
"license": "MIT",
|
| 3441 |
+
"dependencies": {
|
| 3442 |
+
"@babel/runtime": "^7.28.2",
|
| 3443 |
+
"@mui/utils": "^7.2.0",
|
| 3444 |
+
"@mui/x-internals": "8.9.2",
|
| 3445 |
+
"@types/react-transition-group": "^4.4.12",
|
| 3446 |
+
"clsx": "^2.1.1",
|
| 3447 |
+
"prop-types": "^15.8.1",
|
| 3448 |
+
"react-transition-group": "^4.4.5",
|
| 3449 |
+
"reselect": "^5.1.1",
|
| 3450 |
+
"use-sync-external-store": "^1.5.0"
|
| 3451 |
+
},
|
| 3452 |
+
"engines": {
|
| 3453 |
+
"node": ">=14.0.0"
|
| 3454 |
+
},
|
| 3455 |
+
"funding": {
|
| 3456 |
+
"type": "opencollective",
|
| 3457 |
+
"url": "https://opencollective.com/mui-org"
|
| 3458 |
+
},
|
| 3459 |
+
"peerDependencies": {
|
| 3460 |
+
"@emotion/react": "^11.9.0",
|
| 3461 |
+
"@emotion/styled": "^11.8.1",
|
| 3462 |
+
"@mui/material": "^5.15.14 || ^6.0.0 || ^7.0.0",
|
| 3463 |
+
"@mui/system": "^5.15.14 || ^6.0.0 || ^7.0.0",
|
| 3464 |
+
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
| 3465 |
+
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
| 3466 |
+
},
|
| 3467 |
+
"peerDependenciesMeta": {
|
| 3468 |
+
"@emotion/react": {
|
| 3469 |
+
"optional": true
|
| 3470 |
+
},
|
| 3471 |
+
"@emotion/styled": {
|
| 3472 |
+
"optional": true
|
| 3473 |
+
}
|
| 3474 |
+
}
|
| 3475 |
+
},
|
| 3476 |
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
|
| 3477 |
"version": "5.1.1-v1",
|
| 3478 |
"resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
|
|
|
|
| 14243 |
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
|
| 14244 |
}
|
| 14245 |
},
|
| 14246 |
+
"node_modules/prismjs": {
|
| 14247 |
+
"version": "1.30.0",
|
| 14248 |
+
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
|
| 14249 |
+
"integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
|
| 14250 |
+
"license": "MIT",
|
| 14251 |
+
"engines": {
|
| 14252 |
+
"node": ">=6"
|
| 14253 |
+
}
|
| 14254 |
+
},
|
| 14255 |
"node_modules/process-nextick-args": {
|
| 14256 |
"version": "2.0.1",
|
| 14257 |
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
|
|
|
| 14930 |
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
| 14931 |
"license": "MIT"
|
| 14932 |
},
|
| 14933 |
+
"node_modules/reselect": {
|
| 14934 |
+
"version": "5.1.1",
|
| 14935 |
+
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
|
| 14936 |
+
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
|
| 14937 |
+
"license": "MIT"
|
| 14938 |
+
},
|
| 14939 |
"node_modules/resolve": {
|
| 14940 |
"version": "1.22.10",
|
| 14941 |
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
|
|
|
| 17255 |
"requires-port": "^1.0.0"
|
| 17256 |
}
|
| 17257 |
},
|
| 17258 |
+
"node_modules/use-sync-external-store": {
|
| 17259 |
+
"version": "1.5.0",
|
| 17260 |
+
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
|
| 17261 |
+
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
|
| 17262 |
+
"license": "MIT",
|
| 17263 |
+
"peerDependencies": {
|
| 17264 |
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
| 17265 |
+
}
|
| 17266 |
+
},
|
| 17267 |
"node_modules/util-deprecate": {
|
| 17268 |
"version": "1.0.2",
|
| 17269 |
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
package.json
CHANGED
|
@@ -5,13 +5,16 @@
|
|
| 5 |
"dependencies": {
|
| 6 |
"@emotion/styled": "^11.14.1",
|
| 7 |
"@mui/icons-material": "^7.2.0",
|
|
|
|
| 8 |
"@mui/material": "^7.2.0",
|
|
|
|
| 9 |
"@testing-library/dom": "^10.4.0",
|
| 10 |
"@testing-library/jest-dom": "^6.6.3",
|
| 11 |
"@testing-library/react": "^16.3.0",
|
| 12 |
"@testing-library/user-event": "^13.5.0",
|
| 13 |
"axios": "^1.11.0",
|
| 14 |
"jszip": "^3.10.1",
|
|
|
|
| 15 |
"react": "^19.1.0",
|
| 16 |
"react-dom": "^19.1.0",
|
| 17 |
"react-scripts": "5.0.1",
|
|
|
|
| 5 |
"dependencies": {
|
| 6 |
"@emotion/styled": "^11.14.1",
|
| 7 |
"@mui/icons-material": "^7.2.0",
|
| 8 |
+
"@mui/lab": "^7.0.0-beta.15",
|
| 9 |
"@mui/material": "^7.2.0",
|
| 10 |
+
"@mui/x-tree-view": "^8.9.2",
|
| 11 |
"@testing-library/dom": "^10.4.0",
|
| 12 |
"@testing-library/jest-dom": "^6.6.3",
|
| 13 |
"@testing-library/react": "^16.3.0",
|
| 14 |
"@testing-library/user-event": "^13.5.0",
|
| 15 |
"axios": "^1.11.0",
|
| 16 |
"jszip": "^3.10.1",
|
| 17 |
+
"prismjs": "^1.30.0",
|
| 18 |
"react": "^19.1.0",
|
| 19 |
"react-dom": "^19.1.0",
|
| 20 |
"react-scripts": "5.0.1",
|
src/FileUploadForm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import React, { useState } from "react";
|
| 2 |
import axios from "axios";
|
| 3 |
import {
|
| 4 |
Box,
|
|
@@ -17,12 +17,18 @@ import {
|
|
| 17 |
DialogTitle,
|
| 18 |
DialogContent,
|
| 19 |
DialogActions,
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
} from "@mui/material";
|
|
|
|
| 24 |
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
|
| 25 |
import DownloadIcon from "@mui/icons-material/Download";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
const FileUploadForm = () => {
|
| 28 |
const [file, setFile] = useState(null);
|
|
@@ -32,8 +38,83 @@ const FileUploadForm = () => {
|
|
| 32 |
const [loading, setLoading] = useState(false);
|
| 33 |
const [showSnackbar, setShowSnackbar] = useState(false);
|
| 34 |
const [showModal, setShowModal] = useState(false);
|
| 35 |
-
const [fileList, setFileList] = useState([]);
|
| 36 |
const [zipBlob, setZipBlob] = useState(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
const handleDownload = async (e) => {
|
| 39 |
e.preventDefault();
|
|
@@ -58,12 +139,24 @@ const FileUploadForm = () => {
|
|
| 58 |
|
| 59 |
const JSZip = (await import("jszip")).default;
|
| 60 |
const zip = await JSZip.loadAsync(blob);
|
| 61 |
-
const
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
setShowModal(true);
|
| 64 |
} catch (error) {
|
| 65 |
-
console.error("Error
|
| 66 |
-
alert("Failed to generate project.
|
| 67 |
} finally {
|
| 68 |
setLoading(false);
|
| 69 |
}
|
|
@@ -81,94 +174,120 @@ const FileUploadForm = () => {
|
|
| 81 |
setShowModal(false);
|
| 82 |
};
|
| 83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
return (
|
| 85 |
-
<Box
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
>
|
| 96 |
<Paper elevation={6} sx={{ padding: 4, backgroundColor: "#1e1e1e", maxWidth: 600, width: "100%" }}>
|
| 97 |
<Box textAlign="center" my={4}>
|
| 98 |
-
<Typography variant="h4" component="h1">
|
| 99 |
-
🧠 AI Project Generator
|
| 100 |
-
</Typography>
|
| 101 |
</Box>
|
| 102 |
|
| 103 |
-
<Typography variant="h5" gutterBottom color="primary">
|
| 104 |
-
📄 Generate Full-Stack Project from Requirements (TXT or PDF)
|
| 105 |
-
</Typography>
|
| 106 |
-
|
| 107 |
<form onSubmit={handleDownload}>
|
| 108 |
-
<Grid container spacing={2}>
|
| 109 |
-
<Grid item
|
| 110 |
-
<Button
|
| 111 |
-
variant="contained"
|
| 112 |
-
component="label"
|
| 113 |
-
startIcon={<CloudUploadIcon />}
|
| 114 |
-
fullWidth
|
| 115 |
-
>
|
| 116 |
-
{file ? file.name : "Upload Requirement Document"}
|
| 117 |
-
<input
|
| 118 |
-
type="file"
|
| 119 |
-
hidden
|
| 120 |
-
required
|
| 121 |
-
onChange={(e) => setFile(e.target.files[0])}
|
| 122 |
-
accept=".pdf,.txt"
|
| 123 |
-
/>
|
| 124 |
-
</Button>
|
| 125 |
-
</Grid>
|
| 126 |
-
|
| 127 |
-
{/* 👇 Updated: Stack dropdowns one below the other */}
|
| 128 |
-
<Grid item xs={12}>
|
| 129 |
<FormControl fullWidth>
|
| 130 |
-
<
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
<
|
| 138 |
-
</
|
| 139 |
</FormControl>
|
| 140 |
</Grid>
|
| 141 |
|
| 142 |
-
|
| 143 |
-
<
|
| 144 |
-
<
|
| 145 |
-
|
| 146 |
-
<
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
<
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
<MenuItem value="MySQL">MySQL</MenuItem>
|
| 163 |
-
<MenuItem value="SQLite">SQLite</MenuItem>
|
| 164 |
-
<MenuItem value="Firebase">Firebase</MenuItem>
|
| 165 |
-
<MenuItem value="Supabase">Supabase</MenuItem>
|
| 166 |
-
</Select>
|
| 167 |
-
</FormControl>
|
| 168 |
-
</Grid>
|
| 169 |
|
| 170 |
-
|
| 171 |
-
<Grid item xs={12}>
|
| 172 |
<Button
|
| 173 |
type="submit"
|
| 174 |
variant="contained"
|
|
@@ -184,26 +303,69 @@ const FileUploadForm = () => {
|
|
| 184 |
</form>
|
| 185 |
</Paper>
|
| 186 |
|
| 187 |
-
{/*
|
| 188 |
-
<Dialog open={showModal} onClose={() => setShowModal(false)} maxWidth="
|
| 189 |
-
<DialogTitle>📦 Generated Files
|
| 190 |
<DialogContent dividers>
|
| 191 |
-
<
|
| 192 |
-
|
| 193 |
-
<
|
| 194 |
-
<
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
</DialogContent>
|
| 199 |
<DialogActions>
|
| 200 |
-
<Button onClick={handleZipDownload} variant="contained"
|
| 201 |
-
|
| 202 |
-
</Button>
|
| 203 |
-
<Button onClick={() => setShowModal(false)}>Cancel</Button>
|
| 204 |
</DialogActions>
|
| 205 |
</Dialog>
|
| 206 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 207 |
{/* ✅ Success Snackbar */}
|
| 208 |
<Snackbar
|
| 209 |
open={showSnackbar}
|
|
@@ -211,7 +373,7 @@ const FileUploadForm = () => {
|
|
| 211 |
onClose={() => setShowSnackbar(false)}
|
| 212 |
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
|
| 213 |
>
|
| 214 |
-
<Alert
|
| 215 |
✅ ZIP downloaded successfully!
|
| 216 |
</Alert>
|
| 217 |
</Snackbar>
|
|
|
|
| 1 |
+
import React, { useState, useEffect, useRef } from "react";
|
| 2 |
import axios from "axios";
|
| 3 |
import {
|
| 4 |
Box,
|
|
|
|
| 17 |
DialogTitle,
|
| 18 |
DialogContent,
|
| 19 |
DialogActions,
|
| 20 |
+
useMediaQuery,
|
| 21 |
+
Menu,
|
| 22 |
+
MenuItem as ContextMenuItem,
|
| 23 |
} from "@mui/material";
|
| 24 |
+
import { useTheme } from "@mui/material/styles";
|
| 25 |
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
|
| 26 |
import DownloadIcon from "@mui/icons-material/Download";
|
| 27 |
+
import FolderIcon from "@mui/icons-material/Folder";
|
| 28 |
+
import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
|
| 29 |
+
import { SimpleTreeView, TreeItem } from "@mui/x-tree-view";
|
| 30 |
+
import Prism from './prism-setup';
|
| 31 |
+
import { detectLanguage } from './utils/languageDetect';
|
| 32 |
|
| 33 |
const FileUploadForm = () => {
|
| 34 |
const [file, setFile] = useState(null);
|
|
|
|
| 38 |
const [loading, setLoading] = useState(false);
|
| 39 |
const [showSnackbar, setShowSnackbar] = useState(false);
|
| 40 |
const [showModal, setShowModal] = useState(false);
|
|
|
|
| 41 |
const [zipBlob, setZipBlob] = useState(null);
|
| 42 |
+
const [fileListInfo, setFileListInfo] = useState({});
|
| 43 |
+
const [selectedFile, setSelectedFile] = useState(null);
|
| 44 |
+
const [expandedIds, setExpandedIds] = useState([]); // ✅ array, not Set
|
| 45 |
+
|
| 46 |
+
const [contextAnchor, setContextAnchor] = useState(null);
|
| 47 |
+
const [contextFile, setContextFile] = useState(null);
|
| 48 |
+
|
| 49 |
+
const codeRef = useRef(null);
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
const theme = useTheme();
|
| 57 |
+
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
| 58 |
+
|
| 59 |
+
const buildTree = (files) => {
|
| 60 |
+
const root = {};
|
| 61 |
+
for (const path in files) {
|
| 62 |
+
const parts = path.split("/");
|
| 63 |
+
let current = root;
|
| 64 |
+
for (let i = 0; i < parts.length; i++) {
|
| 65 |
+
const part = parts[i];
|
| 66 |
+
if (!current[part]) {
|
| 67 |
+
current[part] = i === parts.length - 1 ? files[path] : {};
|
| 68 |
+
}
|
| 69 |
+
current = current[part];
|
| 70 |
+
}
|
| 71 |
+
}
|
| 72 |
+
return root;
|
| 73 |
+
};
|
| 74 |
+
|
| 75 |
+
const renderTree = (node, path = "") => {
|
| 76 |
+
if (!node || typeof node !== "object") return null;
|
| 77 |
+
|
| 78 |
+
return Object.entries(node).map(([key, value]) => {
|
| 79 |
+
const fullPath = path ? `${path}/${key}` : key;
|
| 80 |
+
const itemId = fullPath.replaceAll("/", "-");
|
| 81 |
+
const isFile = value && typeof value.preview !== "undefined";
|
| 82 |
+
|
| 83 |
+
return (
|
| 84 |
+
<TreeItem
|
| 85 |
+
key={fullPath}
|
| 86 |
+
itemId={itemId}
|
| 87 |
+
label={
|
| 88 |
+
<Box
|
| 89 |
+
display="flex"
|
| 90 |
+
alignItems="center"
|
| 91 |
+
onContextMenu={(e) => handleContextMenu(e, fullPath, value)}
|
| 92 |
+
>
|
| 93 |
+
{isFile ? <InsertDriveFileIcon sx={{ mr: 1 }} /> : <FolderIcon sx={{ mr: 1 }} />}
|
| 94 |
+
<Typography variant="body2">
|
| 95 |
+
{key}
|
| 96 |
+
{isFile ? ` (${(value.size / 1024).toFixed(1)} KB)` : ""}
|
| 97 |
+
</Typography>
|
| 98 |
+
</Box>
|
| 99 |
+
}
|
| 100 |
+
onClick={() => {
|
| 101 |
+
if (isFile) {
|
| 102 |
+
setSelectedFile({ name: fullPath, content: value.preview });
|
| 103 |
+
Prism.highlightAll();
|
| 104 |
+
} else {
|
| 105 |
+
setExpandedIds((prev) =>
|
| 106 |
+
prev.includes(itemId)
|
| 107 |
+
? prev.filter((id) => id !== itemId) // collapse
|
| 108 |
+
: [...prev, itemId] // expand
|
| 109 |
+
);
|
| 110 |
+
}
|
| 111 |
+
}}
|
| 112 |
+
>
|
| 113 |
+
{!isFile && renderTree(value, fullPath)}
|
| 114 |
+
</TreeItem>
|
| 115 |
+
);
|
| 116 |
+
});
|
| 117 |
+
};
|
| 118 |
|
| 119 |
const handleDownload = async (e) => {
|
| 120 |
e.preventDefault();
|
|
|
|
| 139 |
|
| 140 |
const JSZip = (await import("jszip")).default;
|
| 141 |
const zip = await JSZip.loadAsync(blob);
|
| 142 |
+
const fileInfo = {};
|
| 143 |
+
await Promise.all(
|
| 144 |
+
Object.entries(zip.files).map(async ([name, file]) => {
|
| 145 |
+
if (!file.dir) {
|
| 146 |
+
const content = await file.async("string");
|
| 147 |
+
fileInfo[name] = {
|
| 148 |
+
size: file._data.uncompressedSize,
|
| 149 |
+
preview: content.slice(0, 1000),
|
| 150 |
+
};
|
| 151 |
+
}
|
| 152 |
+
})
|
| 153 |
+
);
|
| 154 |
+
setFileListInfo(fileInfo);
|
| 155 |
+
setExpandedIds([]); // reset tree state
|
| 156 |
setShowModal(true);
|
| 157 |
} catch (error) {
|
| 158 |
+
console.error("Error:", error);
|
| 159 |
+
alert("Failed to generate project.");
|
| 160 |
} finally {
|
| 161 |
setLoading(false);
|
| 162 |
}
|
|
|
|
| 174 |
setShowModal(false);
|
| 175 |
};
|
| 176 |
|
| 177 |
+
const handleContextMenu = (event, filename, value) => {
|
| 178 |
+
event.preventDefault();
|
| 179 |
+
if (typeof value.preview === "undefined") return; // not a file
|
| 180 |
+
setContextFile({ name: filename, content: value.preview });
|
| 181 |
+
setContextAnchor(event.currentTarget);
|
| 182 |
+
};
|
| 183 |
+
|
| 184 |
+
const handleDownloadFile = () => {
|
| 185 |
+
if (!contextFile) return;
|
| 186 |
+
const blob = new Blob([contextFile.content], { type: "text/plain" });
|
| 187 |
+
const a = document.createElement("a");
|
| 188 |
+
a.href = URL.createObjectURL(blob);
|
| 189 |
+
a.download = contextFile.name.split("/").pop();
|
| 190 |
+
a.click();
|
| 191 |
+
setContextAnchor(null);
|
| 192 |
+
};
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
// ✅ Expand/collapse logic
|
| 196 |
+
const expandAll = () => {
|
| 197 |
+
const allPaths = Object.keys(fileListInfo); // files only
|
| 198 |
+
const allIds = new Set();
|
| 199 |
+
|
| 200 |
+
allPaths.forEach((filePath) => {
|
| 201 |
+
const parts = filePath.split("/");
|
| 202 |
+
for (let i = 1; i <= parts.length; i++) {
|
| 203 |
+
const partialPath = parts.slice(0, i).join("/");
|
| 204 |
+
allIds.add(partialPath.replaceAll("/", "-")); // folder or file
|
| 205 |
+
}
|
| 206 |
+
});
|
| 207 |
+
|
| 208 |
+
setExpandedIds(Array.from(allIds));
|
| 209 |
+
};
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
const collapseAll = () => {
|
| 213 |
+
setExpandedIds([]); // ✅ empty array
|
| 214 |
+
};
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
const { lang, code } = React.useMemo(() => {
|
| 220 |
+
if (selectedFile && selectedFile.content) {
|
| 221 |
+
const lines = selectedFile.content.split('\n');
|
| 222 |
+
const firstLine = lines[0].trim();
|
| 223 |
+
const hasLang = /^[a-zA-Z]+$/.test(firstLine);
|
| 224 |
+
const lang = hasLang ? firstLine.toLowerCase() : detectLanguage(selectedFile.content) || 'markdown';
|
| 225 |
+
const code = hasLang ? lines.slice(1).join('\n') : selectedFile.content;
|
| 226 |
+
return { lang, code };
|
| 227 |
+
}
|
| 228 |
+
return { lang: 'markdown', code: '' };
|
| 229 |
+
}, [selectedFile]);
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
useEffect(() => {
|
| 233 |
+
if (codeRef.current) {
|
| 234 |
+
Prism.highlightElement(codeRef.current);
|
| 235 |
+
}
|
| 236 |
+
}, [code, lang]);
|
| 237 |
return (
|
| 238 |
+
<Box sx={{
|
| 239 |
+
backgroundColor: "#121212",
|
| 240 |
+
minHeight: "100vh",
|
| 241 |
+
color: "#fff",
|
| 242 |
+
padding: 4,
|
| 243 |
+
display: "flex",
|
| 244 |
+
justifyContent: "center",
|
| 245 |
+
alignItems: "center",
|
| 246 |
+
flexDirection: "column",
|
| 247 |
+
}}>
|
|
|
|
| 248 |
<Paper elevation={6} sx={{ padding: 4, backgroundColor: "#1e1e1e", maxWidth: 600, width: "100%" }}>
|
| 249 |
<Box textAlign="center" my={4}>
|
| 250 |
+
<Typography variant="h4" component="h1">🧠 AI - Full-Stack Project Generator</Typography>
|
|
|
|
|
|
|
| 251 |
</Box>
|
| 252 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 253 |
<form onSubmit={handleDownload}>
|
| 254 |
+
<Grid container spacing={2} direction="column">
|
| 255 |
+
<Grid item>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 256 |
<FormControl fullWidth>
|
| 257 |
+
<Button
|
| 258 |
+
variant="contained"
|
| 259 |
+
component="label"
|
| 260 |
+
startIcon={<CloudUploadIcon />}
|
| 261 |
+
fullWidth
|
| 262 |
+
>
|
| 263 |
+
{file ? file.name : "Upload Requirement Document"}
|
| 264 |
+
<input type="file" hidden required onChange={(e) => setFile(e.target.files[0])} accept=".pdf,.txt" />
|
| 265 |
+
</Button>
|
| 266 |
</FormControl>
|
| 267 |
</Grid>
|
| 268 |
|
| 269 |
+
{["Frontend", "Backend", "Database"].map((label, idx) => (
|
| 270 |
+
<Grid item key={label}>
|
| 271 |
+
<FormControl fullWidth>
|
| 272 |
+
<InputLabel>{label}</InputLabel>
|
| 273 |
+
<Select
|
| 274 |
+
value={label === "Frontend" ? frontend : label === "Backend" ? backend : database}
|
| 275 |
+
onChange={(e) => {
|
| 276 |
+
if (label === "Frontend") setFrontend(e.target.value);
|
| 277 |
+
else if (label === "Backend") setBackend(e.target.value);
|
| 278 |
+
else setDatabase(e.target.value);
|
| 279 |
+
}}
|
| 280 |
+
label={label}
|
| 281 |
+
>
|
| 282 |
+
{label === "Frontend" && ["React", "Angular", "Vue", "Next.js", "Svelte", "HTML/CSS/JS"].map(opt => <MenuItem key={opt} value={opt}>{opt}</MenuItem>)}
|
| 283 |
+
{label === "Backend" && ["Flask", "Node.js", "Django", "Express.js", "Spring Boot", "FastAPI"].map(opt => <MenuItem key={opt} value={opt}>{opt}</MenuItem>)}
|
| 284 |
+
{label === "Database" && ["PostgreSQL", "MongoDB", "MySQL", "SQLite", "Firebase", "Supabase"].map(opt => <MenuItem key={opt} value={opt}>{opt}</MenuItem>)}
|
| 285 |
+
</Select>
|
| 286 |
+
</FormControl>
|
| 287 |
+
</Grid>
|
| 288 |
+
))}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
|
| 290 |
+
<Grid item>
|
|
|
|
| 291 |
<Button
|
| 292 |
type="submit"
|
| 293 |
variant="contained"
|
|
|
|
| 303 |
</form>
|
| 304 |
</Paper>
|
| 305 |
|
| 306 |
+
{/* 📦 Preview Dialog */}
|
| 307 |
+
<Dialog open={showModal} onClose={() => setShowModal(false)} maxWidth="md" fullWidth>
|
| 308 |
+
<DialogTitle>📦 Generated Files</DialogTitle>
|
| 309 |
<DialogContent dividers>
|
| 310 |
+
<Grid container spacing={2}>
|
| 311 |
+
<Grid item xs={12} md={5}>
|
| 312 |
+
<Box mb={1} display="flex" gap={1}>
|
| 313 |
+
<Button size="small" variant="outlined" onClick={expandAll}>Expand All</Button>
|
| 314 |
+
<Button size="small" variant="outlined" onClick={collapseAll}>Collapse All</Button>
|
| 315 |
+
</Box>
|
| 316 |
+
<SimpleTreeView
|
| 317 |
+
expandedItems={expandedIds}
|
| 318 |
+
onExpandedItemsChange={(newItems) => {
|
| 319 |
+
if (Array.isArray(newItems)) {
|
| 320 |
+
setExpandedIds(newItems); // ✅ directly set array
|
| 321 |
+
} else {
|
| 322 |
+
console.warn("Unexpected expandedItems:", newItems);
|
| 323 |
+
setExpandedIds([]);
|
| 324 |
+
}
|
| 325 |
+
}}
|
| 326 |
+
onItemToggle={(itemId, isExpanded) => {
|
| 327 |
+
setExpandedIds((prev) =>
|
| 328 |
+
isExpanded ? [...prev, itemId] : prev.filter((id) => id !== itemId)
|
| 329 |
+
);
|
| 330 |
+
}}
|
| 331 |
+
>
|
| 332 |
+
{renderTree(buildTree(fileListInfo))}
|
| 333 |
+
</SimpleTreeView>
|
| 334 |
+
</Grid>
|
| 335 |
+
|
| 336 |
+
<Grid item xs={12} md={7}>
|
| 337 |
+
{selectedFile ? (
|
| 338 |
+
<>
|
| 339 |
+
<Typography variant="subtitle1" gutterBottom>{selectedFile.name}</Typography>
|
| 340 |
+
<Paper variant="outlined" sx={{ p: 2, maxHeight: 400, overflowY: "auto", backgroundColor: "#1e1e1e" }}>
|
| 341 |
+
<pre className={`line-numbers language-${lang}`} style={{ borderRadius: '8px', overflowX: 'auto' }}>
|
| 342 |
+
<code ref={codeRef} className={`language-${lang}`}>
|
| 343 |
+
{code}
|
| 344 |
+
</code>
|
| 345 |
+
</pre>
|
| 346 |
+
</Paper>
|
| 347 |
+
</>
|
| 348 |
+
) : (
|
| 349 |
+
<Typography color="text.secondary">Select a file to preview its content</Typography>
|
| 350 |
+
)}
|
| 351 |
+
</Grid>
|
| 352 |
+
</Grid>
|
| 353 |
</DialogContent>
|
| 354 |
<DialogActions>
|
| 355 |
+
<Button onClick={handleZipDownload} variant="contained">Download ZIP</Button>
|
| 356 |
+
<Button onClick={() => setShowModal(false)}>Close</Button>
|
|
|
|
|
|
|
| 357 |
</DialogActions>
|
| 358 |
</Dialog>
|
| 359 |
|
| 360 |
+
{/* 🎯 Context Menu for Download */}
|
| 361 |
+
<Menu
|
| 362 |
+
anchorEl={contextAnchor}
|
| 363 |
+
open={Boolean(contextAnchor)}
|
| 364 |
+
onClose={() => setContextAnchor(null)}
|
| 365 |
+
>
|
| 366 |
+
<ContextMenuItem onClick={handleDownloadFile}>📥 Download File</ContextMenuItem>
|
| 367 |
+
</Menu>
|
| 368 |
+
|
| 369 |
{/* ✅ Success Snackbar */}
|
| 370 |
<Snackbar
|
| 371 |
open={showSnackbar}
|
|
|
|
| 373 |
onClose={() => setShowSnackbar(false)}
|
| 374 |
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
|
| 375 |
>
|
| 376 |
+
<Alert severity="success" sx={{ width: "100%" }} onClose={() => setShowSnackbar(false)}>
|
| 377 |
✅ ZIP downloaded successfully!
|
| 378 |
</Alert>
|
| 379 |
</Snackbar>
|
src/prism-setup.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// src/prism-setup.js
|
| 2 |
+
import Prism from 'prismjs';
|
| 3 |
+
|
| 4 |
+
// Prism core styles and plugins
|
| 5 |
+
import 'prismjs/themes/prism-tomorrow.css';
|
| 6 |
+
import 'prismjs/plugins/line-numbers/prism-line-numbers.css';
|
| 7 |
+
import 'prismjs/plugins/line-numbers/prism-line-numbers';
|
| 8 |
+
|
| 9 |
+
// Required languages
|
| 10 |
+
import 'prismjs/components/prism-clike';
|
| 11 |
+
import 'prismjs/components/prism-markup-templating';
|
| 12 |
+
import 'prismjs/components/prism-python';
|
| 13 |
+
import 'prismjs/components/prism-javascript';
|
| 14 |
+
import 'prismjs/components/prism-typescript';
|
| 15 |
+
import 'prismjs/components/prism-java';
|
| 16 |
+
import 'prismjs/components/prism-c';
|
| 17 |
+
import 'prismjs/components/prism-cpp';
|
| 18 |
+
import 'prismjs/components/prism-bash';
|
| 19 |
+
import 'prismjs/components/prism-shell-session';
|
| 20 |
+
import 'prismjs/components/prism-sql';
|
| 21 |
+
import 'prismjs/components/prism-markup'; // HTML
|
| 22 |
+
import 'prismjs/components/prism-css';
|
| 23 |
+
import 'prismjs/components/prism-go';
|
| 24 |
+
import 'prismjs/components/prism-php';
|
| 25 |
+
import 'prismjs/components/prism-ruby';
|
| 26 |
+
import 'prismjs/components/prism-kotlin';
|
| 27 |
+
import 'prismjs/components/prism-swift';
|
| 28 |
+
import 'prismjs/components/prism-rust';
|
| 29 |
+
import 'prismjs/components/prism-scala';
|
| 30 |
+
import 'prismjs/components/prism-dart';
|
| 31 |
+
|
| 32 |
+
export default Prism;
|
src/utils/languageDetect.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// utils/languageDetect.js
|
| 2 |
+
|
| 3 |
+
const escapeRegExp = (string) =>
|
| 4 |
+
string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
| 5 |
+
|
| 6 |
+
export const detectLanguage = (code = '') => {
|
| 7 |
+
const language_keywords = {
|
| 8 |
+
python: ['def ', 'print(', 'import ', 'class '],
|
| 9 |
+
javascript: ['function ', 'console.log(', 'let ', 'const ', 'document.getElementById'],
|
| 10 |
+
typescript: ['interface ', 'type ', 'let ', 'const ', ': string', ': number'],
|
| 11 |
+
java: ['import java.', 'ArrayList<', 'System.out', 'void main(', 'public class', 'new '],
|
| 12 |
+
c: ['#include <stdio.h>', 'printf(', 'scanf(', 'int main('],
|
| 13 |
+
cpp: ['#include', 'std::', 'cout <<', 'cin >>'],
|
| 14 |
+
bash: ['#!/bin/bash', 'echo ', 'cd ', 'ls', 'pwd'],
|
| 15 |
+
shell: ['#!/bin/sh', 'echo ', 'export ', 'fi'],
|
| 16 |
+
sql: ['SELECT ', 'INSERT ', 'UPDATE ', 'FROM ', 'WHERE ', 'JOIN ', 'DELETE '],
|
| 17 |
+
html: ['<!DOCTYPE html>', '<html>', '<div>', '<script>'],
|
| 18 |
+
css: ['color:', 'font-size:', 'margin:', 'padding:'],
|
| 19 |
+
go: ['package main', 'fmt.Println', 'func main()'],
|
| 20 |
+
php: ['<?php', 'echo ', '$_', '->'],
|
| 21 |
+
ruby: ['def ', 'puts ', 'end', 'class '],
|
| 22 |
+
kotlin: ['fun main(', 'val ', 'var ', 'println('],
|
| 23 |
+
swift: ['import SwiftUI', 'struct ', 'var body:', 'Text('],
|
| 24 |
+
rust: ['fn main()', 'println!', 'let mut'],
|
| 25 |
+
scala: ['object ', 'def ', 'val ', 'println('],
|
| 26 |
+
dart: ['void main()', 'print(', 'var ', 'class '],
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
let bestMatch = 'plaintext';
|
| 30 |
+
let maxScore = 0;
|
| 31 |
+
|
| 32 |
+
for (const [lang, keywords] of Object.entries(language_keywords)) {
|
| 33 |
+
let score = 0;
|
| 34 |
+
|
| 35 |
+
for (const keyword of keywords) {
|
| 36 |
+
const regex = new RegExp(escapeRegExp(keyword), 'g');
|
| 37 |
+
const matches = (code.match(regex) || []).length;
|
| 38 |
+
score += matches * Math.max(1, keyword.length / 4);
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
if (score > maxScore) {
|
| 42 |
+
maxScore = score;
|
| 43 |
+
bestMatch = lang;
|
| 44 |
+
}
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
return bestMatch;
|
| 48 |
+
};
|