diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index b51c4dc..0000000 Binary files a/bun.lockb and /dev/null differ diff --git a/package-lock.json b/package-lock.json index ce1ee08..96a6381 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,9 +10,16 @@ "dependencies": { "@astrojs/node": "^8.3.3", "@astrojs/preact": "^3.5.3", + "@fontsource-variable/fira-code": "^5.1.0", + "@fontsource-variable/inter": "^5.1.0", + "@fontsource-variable/material-symbols-outlined": "^5.1.0", + "@uiw/codemirror-theme-github": "^4.23.2", + "@uiw/react-codemirror": "^4.23.2", + "@uiw/react-monacoeditor": "^3.6.0", "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", "astro": "^4.15.6", + "codemirror": "^5.65.17", "express": "^4.21.0", "node-pty": "^1.0.0", "preact": "^10.24.0", @@ -416,6 +423,18 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.25.0", "license": "MIT", @@ -456,6 +475,101 @@ "node": ">=6.9.0" } }, + "node_modules/@codemirror/autocomplete": { + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.1.tgz", + "integrity": "sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + }, + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.2.tgz", + "integrity": "sha512-Fq7eWOl1Rcbrfn6jD8FPCj9Auaxdm5nIK5RYOeW7ughnd/rY5AmPg6b+CfsG39ZHdwiwe8lde3q8uR7CF5S0yQ==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.2.tgz", + "integrity": "sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.1.tgz", + "integrity": "sha512-IZ0Y7S4/bpaunwggW2jYqwLuHj0QtESf5xcROewY6+lDNwZ/NzvR4t+vpYgg9m7V8UXLPYqG+lu3DF470E5Oxg==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.6", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.6.tgz", + "integrity": "sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz", + "integrity": "sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==", + "license": "MIT" + }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz", + "integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.33.0", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.33.0.tgz", + "integrity": "sha512-AroaR3BvnjRW8fiZBalAaK+ZzB5usGgI014YKElYZvQdNH5ZIidHlO+cyf/2rWzyBFRkvG6VhiXeAEbC53P2YQ==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.4.0", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@esbuild/linux-x64": { "version": "0.21.5", "cpu": [ @@ -470,6 +584,24 @@ "node": ">=12" } }, + "node_modules/@fontsource-variable/fira-code": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@fontsource-variable/fira-code/-/fira-code-5.1.0.tgz", + "integrity": "sha512-fwJbJLvyZ2BhgBSPYCNsrQ6IFQTpRu9GWXY8N20wHTpbhV0Ro5QJihiZV060Ay3kVR6IVH/oSVe/cr7Ube28gg==", + "license": "OFL-1.1" + }, + "node_modules/@fontsource-variable/inter": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.1.0.tgz", + "integrity": "sha512-Wj2dUGP0vUpxRGQTXQTCNJO+aLcFcQm+gUPXfj/aS877bQkEPBPv9JvZJpwdm2vzelt8NTZ+ausKlBCJjh2XIg==", + "license": "OFL-1.1" + }, + "node_modules/@fontsource-variable/material-symbols-outlined": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@fontsource-variable/material-symbols-outlined/-/material-symbols-outlined-5.1.0.tgz", + "integrity": "sha512-t5lXmVtDZDha0iYp9//cwaftAjHrcLmWeWi6NILWsV/SvpQ8vnRQbVxMK7VIxHJy3czm4diHYA7I8w6MmqbLfQ==", + "license": "Apache-2.0" + }, "node_modules/@img/sharp-libvips-linux-x64": { "version": "1.0.4", "cpu": [ @@ -576,6 +708,30 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lezer/common": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz", + "integrity": "sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==", + "license": "MIT" + }, + "node_modules/@lezer/highlight": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", + "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", + "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "license": "MIT", @@ -1009,6 +1165,119 @@ "@types/node": "*" } }, + "node_modules/@uiw/codemirror-extensions-basic-setup": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.23.2.tgz", + "integrity": "sha512-eacivkj7wzskl2HBYs4rfN0CbYlsSQh5ADtOYWTpc8Txm4ONw8RTi4/rxF6Ks2vdaovizewU5QaHximbxoNTrw==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@codemirror/autocomplete": ">=6.0.0", + "@codemirror/commands": ">=6.0.0", + "@codemirror/language": ">=6.0.0", + "@codemirror/lint": ">=6.0.0", + "@codemirror/search": ">=6.0.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/view": ">=6.0.0" + } + }, + "node_modules/@uiw/codemirror-theme-github": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-github/-/codemirror-theme-github-4.23.2.tgz", + "integrity": "sha512-CFH6JVwQ8MPRiY32Fy13I+iiD56eYE8jBpGjtPZPiYDcxAmRNU++x79vCguO3dpXUvqSJ9bPjcHbz4wOXxCVEw==", + "license": "MIT", + "dependencies": { + "@uiw/codemirror-themes": "4.23.2" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, + "node_modules/@uiw/codemirror-themes": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.23.2.tgz", + "integrity": "sha512-g8x+oPqgbzxXSkHhRf7e1AM1mI9/Nl3URReS89pHitRKv8MZNrE+ey+HE8ycfNXRUatrb6zTSRV3M75uoZwNYw==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@codemirror/language": ">=6.0.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/view": ">=6.0.0" + } + }, + "node_modules/@uiw/react-codemirror": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.23.2.tgz", + "integrity": "sha512-MmFL6P5V1Mr81JLkJyWNedfxENKdRhsvyU7Izji9wp337m8dqRAz7rCF5XWarGKx+iQ7q2H5ryl07nLqKLSvtQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.6", + "@codemirror/commands": "^6.1.0", + "@codemirror/state": "^6.1.1", + "@codemirror/theme-one-dark": "^6.0.0", + "@uiw/codemirror-extensions-basic-setup": "4.23.2", + "codemirror": "^6.0.0" + }, + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + }, + "peerDependencies": { + "@babel/runtime": ">=7.11.0", + "@codemirror/state": ">=6.0.0", + "@codemirror/theme-one-dark": ">=6.0.0", + "@codemirror/view": ">=6.0.0", + "codemirror": ">=6.0.0", + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@uiw/react-codemirror/node_modules/codemirror": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, + "node_modules/@uiw/react-monacoeditor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@uiw/react-monacoeditor/-/react-monacoeditor-3.6.0.tgz", + "integrity": "sha512-TByRDQvJLIzdyFhpkRdWz3g05fydBa73iTDKyHJ7W3Ic2fV+wEO/DX9HKOGk6f3r/hTdGOLDd4iytr8W7PFqmA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.16.7", + "monaco-editor": "^0.44.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "license": "ISC" @@ -1603,6 +1872,12 @@ "node": ">=6" } }, + "node_modules/codemirror": { + "version": "5.65.17", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.17.tgz", + "integrity": "sha512-1zOsUx3lzAOu/gnMAZkQ9kpIHcPYOc9y1Fbm2UVk5UBPkdq380nhkelG0qUwm1f7wPvTbndu9ZYlug35EwAZRQ==", + "license": "MIT" + }, "node_modules/color": { "version": "4.2.3", "license": "MIT", @@ -1713,6 +1988,12 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "6.0.5", "dev": true, @@ -3451,6 +3732,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "license": "ISC", @@ -4301,6 +4595,12 @@ "node": "*" } }, + "node_modules/monaco-editor": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.44.0.tgz", + "integrity": "sha512-5SmjNStN6bSuSE5WPT2ZV+iYn1/yI9sd4Igtk23ChvqB7kDk9lZbB9F5frsuvpB+2njdIeGGFf2G4gbE6rCC9Q==", + "license": "MIT" + }, "node_modules/mrmime": { "version": "2.0.0", "license": "MIT", @@ -4893,6 +5193,33 @@ "node": ">= 0.8" } }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "dev": true, @@ -4906,6 +5233,12 @@ "node": ">=4" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "license": "MIT" + }, "node_modules/regex": { "version": "4.3.2", "license": "MIT" @@ -5254,6 +5587,16 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/section-matter": { "version": "1.0.0", "license": "MIT", @@ -5732,6 +6075,12 @@ "node": ">=0.10.0" } }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "5.5.0", "dev": true, @@ -6237,6 +6586,12 @@ } } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, "node_modules/web-namespaces": { "version": "2.0.1", "license": "MIT", diff --git a/package.json b/package.json index 3cd72ce..a889385 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,16 @@ "dependencies": { "@astrojs/node": "^8.3.3", "@astrojs/preact": "^3.5.3", + "@fontsource-variable/fira-code": "^5.1.0", + "@fontsource-variable/inter": "^5.1.0", + "@fontsource-variable/material-symbols-outlined": "^5.1.0", + "@uiw/codemirror-theme-github": "^4.23.2", + "@uiw/react-codemirror": "^4.23.2", + "@uiw/react-monacoeditor": "^3.6.0", "@xterm/addon-fit": "^0.10.0", "@xterm/xterm": "^5.5.0", "astro": "^4.15.6", + "codemirror": "^5.65.17", "express": "^4.21.0", "node-pty": "^1.0.0", "preact": "^10.24.0", diff --git a/src/client/components/Editor.jsx b/src/client/components/Editor.jsx new file mode 100644 index 0000000..082a9a0 --- /dev/null +++ b/src/client/components/Editor.jsx @@ -0,0 +1,3 @@ +export const Editor = ({}) => { + return +} diff --git a/src/client/components/TreeView.jsx b/src/client/components/TreeView.jsx new file mode 100644 index 0000000..43a86aa --- /dev/null +++ b/src/client/components/TreeView.jsx @@ -0,0 +1,69 @@ +export const EXAMPLE_TREE = { + type: 'root', + children: [ + { + type: 'folder', + name: 'bin/', + children: [ + { + type: 'file', + name: 'a.out', + }, + ], + }, + { + type: 'file', + name: 'main.c', + }, + { + type: 'file', + name: 'data.csv', + }, + ], +} + +const flattenTree = (node, depth = 0) => { + if (node.type === 'root') return node.children.flatMap(entry => flattenTree(entry, depth)) + + if (node.type === 'folder') + return [ + { + depth, + type: 'folder', + name: node.name, + }, + ...node.children.flatMap(entry => flattenTree(entry, depth + 1)), + ] + + if (node.type === 'file') + return [ + { + depth, + type: 'file', + name: node.name, + }, + ] + + throw new Error(`invalid node type "${node?.type ?? ''}"`) +} + +const ICONS = { + ['folder']: 'folder', + ['file']: 'description', +} + +export const TreeView = ({ value }) => { + const flatNodes = flattenTree(value) + + return ( +
+ {flatNodes.map(node => ( +
+
{ICONS[node.type]}
+
{node.name}
+
+
+ ))} +
+ ) +} diff --git a/src/client/fonts.css b/src/client/fonts.css new file mode 100644 index 0000000..9d2886f --- /dev/null +++ b/src/client/fonts.css @@ -0,0 +1,47 @@ +/* fira-mono-latin-400-normal */ +@font-face { + font-family: 'Fira Mono'; + font-style: normal; + font-display: swap; + font-weight: 400; + src: url(https://cdn.jsdelivr.net/fontsource/fonts/fira-mono@latest/latin-400-normal.woff2) format('woff2'), + url(https://cdn.jsdelivr.net/fontsource/fonts/fira-mono@latest/latin-400-normal.woff) format('woff'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* fira-mono-latin-500-normal */ +@font-face { + font-family: 'Fira Mono'; + font-style: normal; + font-display: swap; + font-weight: 500; + src: url(https://cdn.jsdelivr.net/fontsource/fonts/fira-mono@latest/latin-500-normal.woff2) format('woff2'), + url(https://cdn.jsdelivr.net/fontsource/fonts/fira-mono@latest/latin-500-normal.woff) format('woff'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* fira-mono-latin-700-normal */ +@font-face { + font-family: 'Fira Mono'; + font-style: normal; + font-display: swap; + font-weight: 700; + src: url(https://cdn.jsdelivr.net/fontsource/fonts/fira-mono@latest/latin-700-normal.woff2) format('woff2'), + url(https://cdn.jsdelivr.net/fontsource/fonts/fira-mono@latest/latin-700-normal.woff) format('woff'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* inter-latin-wght-normal */ +@font-face { + font-family: 'Inter Variable'; + font-style: italic; + font-display: swap; + font-weight: 100 900; + src: url(https://cdn.jsdelivr.net/fontsource/fonts/inter:vf@latest/latin-opsz-italic.woff2) + format('woff2-variations'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, + U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/src/client/style.css b/src/client/style.css index 7ebf586..bd6f20f 100644 --- a/src/client/style.css +++ b/src/client/style.css @@ -24,8 +24,39 @@ body { -moz-osx-font-smoothing: grayscale; } +/* Utility */ + +.flex-row { + display: flex; + flex-direction: row; + + .flex-grow { + flex-grow: 1; + } +} + /* Components */ +.material-symbols-outlined { + font-family: 'Material Symbols Outlined Variable'; + font-weight: normal; + font-style: normal; + font-size: 20px; /* Preferred icon size */ + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + + display: grid; + place-content: center; +} + +.material-symbols-outlined { + font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 20; +} + .xterm { margin: 2rem; padding: 0.5rem; @@ -38,3 +69,462 @@ body { font-family: 'JetBrains Mono', monospace; } } + +textarea.code-editor-prototype { + appearance: none; + resize: none; + outline: none; + border: none; + background: #fff; + + width: 100%; + height: 100%; + + font-family: 'Fira Code Variable', monospace; + font-weight: 400; + font-size: 15px; +} + +input[type='text'] { + appearance: none; + outline: none; + border: none; + background: #fff; + + font-size: 16px; + + border: 1px solid #d9d9d9; + background: #fff; + + padding: 0.25rem 0.5rem; + + border-radius: 0.25rem; + + box-shadow: 0 0.125rem 0.125rem 0 #00000008; + + min-height: 1.75rem; +} + +button, +input[type='submit'], +[role='button'] { + appearance: none; + outline: none; + border: 1px solid #d9d9d9; + background: #fff; + + display: grid; + place-content: center; + place-items: center; + grid-auto-flow: column; + + font-size: 15px; + font-weight: 500; + + padding: 0.25rem 0.5rem; + gap: 0.25rem; + + border-radius: 0.25rem; + + box-shadow: 0 0.125rem 0.125rem 0 #00000008; + + min-height: 1.75rem; + + cursor: pointer; + + &:not(.icon):has(.material-symbols-outlined:first-child) { + padding-left: 0.125rem; + } + + &:hover { + background: #f8f8f8; + } + + &.icon { + padding: 0.25rem; + aspect-ratio: 1 / 1; + } + + &.run { + background: hsl(120, 35%, 46%); + border-color: hsl(120, 38%, 41%); + color: #fff; + + .material-symbols-outlined { + font-variation-settings: 'FILL' 1, 'wght' 300, 'GRAD' 0, 'opsz' 20; + } + + box-shadow: 0 0.125rem 0.2rem 0 hsla(120, 40%, 53%, 0.37); + + &:hover { + background: hsl(120, 35%, 51%); + } + } + + &.flat { + min-height: auto; + border: none; + background: none; + box-shadow: none; + + &.icon { + padding: 0; + } + + &:hover { + background: #0002; + } + } +} + +.user-details { + display: grid; + grid-template-columns: auto 1fr; + grid-template-rows: 1fr 1fr; + + padding: 0.5rem; + column-gap: 0.5rem; + + border: 1px solid #d9d9d9; + border-radius: 0.5rem; + box-shadow: 0 0.125rem 0.125rem 0 #00000008; + + > .profile { + grid-column: 1 / 2; + grid-row: 1 / 3; + + img { + width: 2.5rem; + height: 2.5rem; + object-fit: cover; + } + } + + > .username { + grid-column: 2 / 3; + grid-row: 1 / 2; + + font-size: 16px; + font-weight: 500; + + align-self: end; + } + + > .email { + grid-column: 2 / 3; + grid-row: 2 / 3; + + align-self: start; + + font-size: 14px; + color: #777; + } + + cursor: pointer; + + &:hover { + background: #00000004; + } +} + +.project-details { + display: grid; + grid-template-columns: 1fr auto; + align-content: center; + + padding: 0 0.25rem 0 0.5rem; + column-gap: 0.5rem; + + min-height: 2rem; + + border: 1px solid #d9d9d9; + border-radius: 0.35rem; + box-shadow: 0 0.125rem 0.125rem 0 #00000008; + + font-size: 15px; + font-weight: 450; + + cursor: pointer; + + &:hover { + background: #00000004; + } +} + +.tree-view { + display: grid; + grid-auto-flow: row; + gap: 0.25rem; + + > .entry { + display: grid; + grid-template-columns: auto 1fr auto; + + padding: 0.125rem 0.5rem 0.125rem 0.25rem; + border-radius: 0.35rem; + gap: 0.35rem; + + margin-left: calc(var(--depth) * 1rem); + + cursor: pointer; + + &:hover { + background: #00000006; + } + } +} + +.ide { + user-select: none; + + display: grid; + height: 100%; + + grid-template-columns: 20rem 1fr; + grid-template-rows: 3rem 1fr 33vh auto; + + grid-template-areas: + 'sidebar header' + 'sidebar editor' + 'sidebar terminal' + 'sidebar status'; + + > .sidebar { + grid-area: sidebar; + + display: flex; + flex-direction: column; + + padding: 1rem; + gap: 1rem; + + border-right: 1px solid #d9d9d9; + + .flex-row { + gap: 0.5rem; + } + + > * { + flex-shrink: 0; + } + + .logo { + font-size: 24px; + font-weight: 700; + } + + > .spacer { + flex-grow: 1; + } + + > .section { + display: flex; + flex-direction: column; + gap: 0.5rem; + + /* border-radius: 0.35rem; + + padding: 0.25rem; + + &:hover { + background: #00000004; + } */ + + padding-bottom: 1rem; + border-bottom: 1px solid #d9d9d9; + + > .spoiler { + display: grid; + grid-template-columns: auto 1fr auto; + align-content: center; + + font-weight: 550; + + border-radius: 0.35rem; + padding: 0.35rem; + gap: 0.5rem; + + cursor: pointer; + + &:hover { + background: #00000006; + } + } + } + } + + > .header { + grid-area: header; + + display: grid; + grid-template-columns: 1fr auto; + align-items: center; + + gap: 1rem; + + padding: 0 0.5rem; + + border-bottom: 1px solid #d9d9d9; + + > .search { + place-self: center; + + display: grid; + + width: 100%; + max-width: 40rem; + + position: relative; + + > .material-symbols-outlined { + position: absolute; + + right: 0; + + top: 50%; + transform: translateY(-50%); + + padding-right: 0.35rem; + } + } + + > .actions { + display: grid; + grid-auto-flow: column; + align-items: center; + + gap: 0.5rem; + } + } + + > .tabbed-editor { + grid-area: editor; + + display: grid; + grid-template-rows: auto 1fr; + + /* background: #fafcfe; */ + background: #f5efff; + + > .tabs { + display: grid; + grid-auto-flow: column; + + padding: 0.5rem; + padding-bottom: 0; + + justify-content: start; + + border-bottom: 1px solid #d9d9d9; + + > .tab { + background: #fff; + + border: 1px solid #d9d9d9; + border-bottom: none; + border-top-left-radius: 0.5rem; + border-top-right-radius: 0.5rem; + + display: grid; + grid-template-columns: 1fr auto; + gap: 0.5rem; + + align-items: center; + + padding: 0.35rem; + + font-size: 15px; + font-weight: 450; + + z-index: 1; + transform: translate(0, 1px); + + cursor: pointer; + + > .title { + padding: 0 0 0 0.15rem; + } + + &:not(.active) { + border-bottom: 1px solid #d9d9d9; + + &:hover { + background: #f8f8f8; + } + } + + &:not(:first-child) { + border-left: none; + } + } + } + + > .editor { + background: #fff; + padding: 0.5rem; + } + } + + > .terminal { + grid-area: terminal; + position: relative; + + border-top: 1px solid #d9d9d9; + + display: grid; + grid-template-rows: auto 1fr; + + padding: 0.5rem; + gap: 0.5rem; + + > .actions { + position: absolute; + top: 0; + right: 0; + + display: grid; + grid-auto-flow: column; + gap: 0.25rem; + + padding: 0.5rem; + } + + &:not(:hover) > .actions { + .material-symbols-outlined { + color: #888; + } + } + + > .title { + font-size: 14px; + font-weight: 550; + } + + > .content { + font-family: 'JetBrains Mono', monospace; + font-size: 14px; + } + } + + > .status { + border-top: 1px solid #d9d9d9; + + padding: 0.125rem 0.25rem; + + display: flex; + flex-direction: row; + gap: 0.25rem; + + font-size: 13px; + } +} + +/* Layout */ + +body { + font-family: 'Inter Variable', sans-serif; + font-size: 16px; + font-weight: 400; + + color: #333; +} diff --git a/src/components/Ide.astro b/src/components/Ide.astro new file mode 100644 index 0000000..377b776 --- /dev/null +++ b/src/components/Ide.astro @@ -0,0 +1,116 @@ +--- +import { TreeView, EXAMPLE_TREE } from '@/client/components/TreeView.jsx' +import { Editor } from '@/client/components/Editor.jsx' + +const { project } = Astro.props + +const userName = project.split('/').at(0).slice(1) +const projectName = project.split('/').at(-1) +--- + +
+ +
+ +
+ + +
+
+
+
+
+
main.c
+
+ +
+
+
+
data.csv
+
+ +
+
+
+
+ +
+
+
+
Terminal
+
+ + +
+
+
{`/ # ls`}
+
+
+
Websocket connection active
+
diff --git a/src/layouts/Base.astro b/src/layouts/Base.astro new file mode 100644 index 0000000..3d3e8e5 --- /dev/null +++ b/src/layouts/Base.astro @@ -0,0 +1,25 @@ +--- +import '@fontsource-variable/material-symbols-outlined/full.css' +import '@fontsource-variable/inter/index.css' +import '@fontsource-variable/fira-code/index.css' + +import '@/client/style.css' + +const { title } = Astro.props +--- + + + + + + + + + + {[title, 'Online Code Editor'].filter(Boolean).join(' | ')} + + + + + + diff --git a/src/pages/@[ns]/[...path].astro b/src/pages/@[ns]/[...path].astro new file mode 100644 index 0000000..507d4cb --- /dev/null +++ b/src/pages/@[ns]/[...path].astro @@ -0,0 +1,11 @@ +--- +import Base from '@/layouts/Base.astro' +import Ide from '@/components/Ide.astro' + +const { ns, path } = Astro.params +const fullPath = `@${ns}/${path}` +--- + + + + diff --git a/src/pages/index.astro b/src/pages/index.astro index c8f39d3..528156c 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,23 +1,14 @@ --- import '@xterm/xterm/css/xterm.css' import '../client/style.css' +import Base from '../layouts/Base.astro' --- - - - - - - + +

docker+xterm.js

+
- docker+xterm.js - - -

docker+xterm.js

-
- - - - + + diff --git a/tsconfig.json b/tsconfig.json index 99df2e6..2b701b1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,11 @@ { - "extends": "astro/tsconfigs/base", - "compilerOptions": { - "jsx": "react-jsx", - "jsxImportSource": "preact" - } -} \ No newline at end of file + "extends": "astro/tsconfigs/base", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "preact", + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + } +}