added mock ide ui

main
Antonio De Lucreziis 2 years ago
parent 53f67cd00a
commit 5a447341c3

Binary file not shown.

355
package-lock.json generated

@ -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",

@ -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",

@ -0,0 +1,3 @@
export const Editor = ({}) => {
return <textarea class="code-editor-prototype" spellcheck="false" autocomplete="off"></textarea>
}

@ -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 ?? '<unknown>'}"`)
}
const ICONS = {
['folder']: 'folder',
['file']: 'description',
}
export const TreeView = ({ value }) => {
const flatNodes = flattenTree(value)
return (
<div class="tree-view">
{flatNodes.map(node => (
<div class={['entry', node.type].join(' ')} style={{ '--depth': node.depth }}>
<div class="material-symbols-outlined">{ICONS[node.type]}</div>
<div class="name">{node.name}</div>
<div class="actions"></div>
</div>
))}
</div>
)
}

@ -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;
}

@ -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;
}

@ -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)
---
<div class="ide">
<div class="sidebar">
<div class="logo">PHC / Run</div>
<div class="flex-row">
<button class="icon">
<div class="material-symbols-outlined">home</div>
</button>
<div class="project-details flex-grow">
<div class="title">
{projectName}
</div>
<div class="open">
<div class="material-symbols-outlined">unfold_more</div>
</div>
</div>
</div>
<div class="section">
<div class="spoiler">
<div class="material-symbols-outlined">account_tree</div>
<div class="title">Files</div>
<div class="material-symbols-outlined">keyboard_arrow_down</div>
</div>
<div class="content">
<TreeView client:load value={EXAMPLE_TREE} />
</div>
</div>
<div class="section">
<div class="spoiler">
<div class="material-symbols-outlined">chat</div>
<div class="title">Conversation</div>
<div class="material-symbols-outlined">keyboard_arrow_down</div>
</div>
<div class="content">...</div>
</div>
<div class="section">
<div class="spoiler">
<div class="material-symbols-outlined">settings</div>
<div class="title">Settings</div>
<div class="material-symbols-outlined">keyboard_arrow_down</div>
</div>
</div>
<div class="spacer"></div>
<div class="user-details">
<div class="profile">
<img src={`https://avatar.iran.liara.run/username?username=${userName}`} alt="profile picture" />
</div>
<div class="username">{userName}</div>
<div class="email">{userName}@exmaple.com</div>
</div>
</div>
<div class="header">
<div class="search">
<div class="material-symbols-outlined">search</div>
<input type="text" placeholder="Search a snippet..." />
</div>
<div class="actions">
<button class="icon">
<div class="material-symbols-outlined">terminal</div>
</button>
<button class="run">
<div class="material-symbols-outlined">play_arrow</div>
Run
</button>
</div>
</div>
<div class="tabbed-editor">
<div class="tabs">
<div class="tab active">
<div class="title">main.c</div>
<div class="buttons">
<button class="flat icon">
<div class="material-symbols-outlined">close</div>
</button>
</div>
</div>
<div class="tab">
<div class="title">data.csv</div>
<div class="buttons">
<button class="flat icon">
<div class="material-symbols-outlined">close</div>
</button>
</div>
</div>
</div>
<div class="editor">
<Editor client:load />
</div>
</div>
<div class="terminal">
<div class="title">Terminal</div>
<div class="actions">
<button class="flat icon">
<div class="material-symbols-outlined">delete</div>
</button>
<button class="flat icon">
<div class="material-symbols-outlined">close</div>
</button>
</div>
<div class="content">
<pre><code>{`/ # ls`}</code></pre>
</div>
</div>
<div class="status">Websocket connection active</div>
</div>

@ -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
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>
{[title, 'Online Code Editor'].filter(Boolean).join(' | ')}
</title>
</head>
<body>
<slot />
</body>
</html>

@ -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}`
---
<Base>
<Ide project={fullPath} />
</Base>

@ -1,23 +1,14 @@
---
import '@xterm/xterm/css/xterm.css'
import '../client/style.css'
import Base from '../layouts/Base.astro'
---
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<Base>
<h1>docker+xterm.js</h1>
<div id="terminal"></div>
<title>docker+xterm.js</title>
</head>
<body>
<h1>docker+xterm.js</h1>
<div id="terminal"></div>
<script>
import '../client/term.js'
</script>
</body>
</html>
<script>
import '../client/term.js'
</script>
</Base>

@ -1,7 +1,11 @@
{
"extends": "astro/tsconfigs/base",
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact"
}
}
"extends": "astro/tsconfigs/base",
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "preact",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}