├── public ├── _redirects ├── favicon.png ├── logo192.png ├── logo512.png ├── robots.txt ├── manifest.json └── index.html ├── .gitignore ├── src ├── index.js ├── components │ ├── firebase.js │ ├── authpageillustration.svg │ └── notfound.svg ├── index.css ├── App.js ├── pages │ ├── notfoundpage.jsx │ ├── authpage.jsx │ ├── deploypage.jsx │ ├── projectspage.jsx │ └── editorpage.jsx ├── App.css └── serviceWorker.js ├── package.json └── README.md /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaagrav/Xper/HEAD/public/favicon.png -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaagrav/Xper/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Jaagrav/Xper/HEAD/public/logo512.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want your app to work offline and load faster, you can change 15 | // unregister() to register() below. Note this comes with some pitfalls. 16 | // Learn more about service workers: https://bit.ly/CRA-PWA 17 | serviceWorker.unregister(); 18 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Xper", 3 | "name": "Xper - RealTime Code Editor", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#1A202E", 24 | "background_color": "#0E1218" 25 | } 26 | -------------------------------------------------------------------------------- /src/components/firebase.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase" 2 | 3 | var firebaseConfig = { 4 | apiKey: "AIzaSyBjuzaHS-svU9tHSQTY2gr4KMnpP16iuQM", 5 | authDomain: "the-coder-b3e19.firebaseapp.com", 6 | databaseURL: "https://the-coder-b3e19.firebaseio.com", 7 | projectId: "the-coder-b3e19", 8 | storageBucket: "the-coder-b3e19.appspot.com", 9 | messagingSenderId: "978497464036", 10 | appId: "1:978497464036:web:359cac492154b35006eef1", 11 | measurementId: "G-9N4YJHX2J7" 12 | }; 13 | // Initialize Firebase 14 | firebase.initializeApp(firebaseConfig); 15 | firebase.analytics(); 16 | 17 | export default firebase; -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Comfortaa:wght@500&family=Orbitron&display=swap'); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | -webkit-user-drag: none; 8 | text-decoration: none; 9 | user-select: none; 10 | } 11 | body { 12 | margin: 0; 13 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 14 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 15 | sans-serif; 16 | -webkit-font-smoothing: antialiased; 17 | -moz-osx-font-smoothing: grayscale; 18 | background-color: #0E1218; 19 | } 20 | 21 | code { 22 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 23 | monospace; 24 | } 25 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './App.css'; 3 | import {BrowserRouter as Router, Route, Redirect, Switch} from 'react-router-dom'; 4 | 5 | import Authpage from './pages/authpage'; 6 | import Projectspage from './pages/projectspage'; 7 | import Editorpage from './pages/editorpage'; 8 | import Deploypage from './pages/deploypage'; 9 | import Notfoundpage from './pages/notfoundpage'; 10 | 11 | function App() { 12 | return ( 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | ); 26 | } 27 | 28 | export default App; 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webdev", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@material-ui/core": "^4.11.0", 7 | "@material-ui/icons": "^4.9.1", 8 | "@material-ui/lab": "^4.0.0-alpha.56", 9 | "@testing-library/jest-dom": "^4.2.4", 10 | "@testing-library/react": "^9.3.2", 11 | "@testing-library/user-event": "^7.1.2", 12 | "ace-builds": "^1.4.12", 13 | "firebase": "^7.23.0", 14 | "react": "^16.13.1", 15 | "react-ace": "^9.1.4", 16 | "react-dom": "^16.13.1", 17 | "react-router-dom": "^5.2.0", 18 | "react-scripts": "3.4.3", 19 | "sweetalert2": "^10.5.1" 20 | }, 21 | "scripts": { 22 | "start": "react-scripts start", 23 | "build": "react-scripts build", 24 | "test": "react-scripts test", 25 | "eject": "react-scripts eject" 26 | }, 27 | "eslintConfig": { 28 | "extends": "react-app" 29 | }, 30 | "browserslist": { 31 | "production": [ 32 | ">0.2%", 33 | "not dead", 34 | "not op_mini all" 35 | ], 36 | "development": [ 37 | "last 1 chrome version", 38 | "last 1 firefox version", 39 | "last 1 safari version" 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/pages/notfoundpage.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | 4 | import { makeStyles } from '@material-ui/core/styles'; 5 | 6 | import NotFoundIllustration from '../components/notfound.svg' 7 | 8 | const useStyles = makeStyles((theme) => ({ 9 | brandingName: { 10 | position: 'absolute', 11 | fontFamily: "'Orbitron', sans-serif", 12 | height: "fit-content", 13 | width: "fit-content", 14 | fontSize: '45px', 15 | color: '#50C0FF', 16 | margin: 'auto', 17 | top: '15px', 18 | left: '15px', 19 | }, 20 | nfi: { 21 | position: "absolute", 22 | margin: 'auto', 23 | width: 'calc(100% - 40%)', 24 | top: '0', 25 | right: '0', 26 | left: '0', 27 | bottom: '0', 28 | }, 29 | notfound: { 30 | position: "absolute", 31 | height: 'fit-content', 32 | width: 'fit-content', 33 | margin: 'auto', 34 | color: '#50C0FF', 35 | right: '0', 36 | left: '0', 37 | bottom: 50, 38 | fontFamily: "'Orbitron', sans-serif", 39 | fontSize: '45px', 40 | } 41 | })) 42 | function Notfoundpage() { 43 | document.title = 'Not Found - Xper'; 44 | 45 | const classes = useStyles(); 46 | 47 | return ( 48 |
49 |
Xper
50 | File Not Found 51 |
Not Found
52 |
53 | ) 54 | } 55 | 56 | export default Notfoundpage; 57 | -------------------------------------------------------------------------------- /src/pages/authpage.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useHistory } from 'react-router-dom'; 3 | 4 | import firebase from '../components/firebase'; 5 | 6 | import Button from '@material-ui/core/Button'; 7 | import { makeStyles } from '@material-ui/core/styles'; 8 | 9 | import Illustration1 from '../components/authpageillustration.svg'; 10 | 11 | const useStyles = makeStyles((theme) => ({ 12 | authButton: { 13 | height: "fit-content", 14 | width: "fit-content", 15 | backgroundColor: "#1A202E", 16 | color: "#50C0FF", 17 | padding: "10px 10px", 18 | "&:hover": { 19 | backgroundColor: "#1D2431" 20 | }, 21 | position: "absolute", 22 | margin: "auto", 23 | top: "50px", 24 | right: "0", 25 | left: "0", 26 | bottom: "0", 27 | }, 28 | brandingName: { 29 | fontFamily: "'Orbitron', sans-serif", 30 | color: "#50C0FF", 31 | height: "fit-content", 32 | width: "fit-content", 33 | fontSize: "3rem", 34 | position: "absolute", 35 | margin: "auto", 36 | top: "0", 37 | right: "0", 38 | left: "0", 39 | bottom: "100px", 40 | }, 41 | topBar: { 42 | height: "7px", 43 | width: "100%", 44 | position: "absolute", 45 | margin: "auto", 46 | top: "0", 47 | right: "0", 48 | left: "0", 49 | backgroundColor: "#50C0FF" 50 | } 51 | })); 52 | 53 | function Authpage() { 54 | document.title = "Auth - Xper"; 55 | const classes = useStyles(); 56 | let history = useHistory(); 57 | 58 | let handleSignIn = e => { 59 | var provider = new firebase.auth.GoogleAuthProvider(); 60 | firebase.auth().signInWithPopup(provider) 61 | } 62 | 63 | firebase.auth().onAuthStateChanged(firebaseUser => { 64 | if (firebaseUser) 65 | history.push("/"); 66 | }); 67 | 68 | return ( 69 |
70 |
71 |
Xper
72 | 73 | auth illustration 74 |
75 | ) 76 | } 77 | 78 | export default Authpage; 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Xper Banner](https://i.imgur.com/PdMiPHA.png) 2 | ## Xper 3 | 4 | Xper is a realtime code editor where you can both write and save your code in realtime! The unique thing about Xper is it updates your deployed code in realtime, which means you can code on your computer and immediately be able to check how it looks like on your phone, tablet, and literally everywhere else. Xper is developed in React, which makes it a lightning fast code editor considering everything is being saved remotely. Check it out in the links given below, 5 |
6 | Live at: https://xperbycoder.netlify.app 7 | Source Code: https://github.com/Jaagrav/Xper 8 |
9 | You can create issues in case you detect a bug, and if you know how to fix it, you can work on it yourself and make a PR, I will accept all the PRs that deserve to be accepted, so now you can also become a contributor for Xper!! 10 |
11 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 12 | 13 | ## Available Scripts 14 | 15 | In the project directory, you can run: 16 | 17 | ### `yarn start` 18 | 19 | Runs the app in the development mode.
20 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 21 | 22 | The page will reload if you make edits.
23 | You will also see any lint errors in the console. 24 | 25 | ### `yarn test` 26 | 27 | Launches the test runner in the interactive watch mode.
28 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 29 | 30 | ### `yarn build` 31 | 32 | Builds the app for production to the `build` folder.
33 | It correctly bundles React in production mode and optimizes the build for the best performance. 34 | 35 | The build is minified and the filenames include the hashes.
36 | Your app is ready to be deployed! 37 | 38 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 39 | 40 | ### `yarn eject` 41 | 42 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 43 | 44 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 45 | 46 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 47 | 48 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 49 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .auth-illustration { 2 | position: absolute; 3 | width: 45%; 4 | margin: auto; 5 | bottom: 0;right: 0; 6 | z-index: -1; 7 | max-width: 645px; 8 | } 9 | 10 | @media (max-width: 600px) { 11 | .auth-illustration { 12 | width: 70%; 13 | } 14 | } 15 | 16 | .MuiList-root.MuiMenu-list.MuiList-padding, .MuiSpeedDialAction-fab, .MuiButtonBase-root.MuiFab-root.MuiSpeedDialAction-fab.MuiSpeedDialAction-fabClosed.MuiFab-sizeSmall { 17 | background: #1A202E !important;color: #62B0FF !important; 18 | } 19 | 20 | .MuiButtonBase-root.MuiFab-root.MuiSpeedDial-fab.MuiFab-primary, .MuiSpeedDial-root.MuiSpeedDial-directionDown.makeStyles-speedDial-6, .MuiFab-label { 21 | height: 30px !important; 22 | background: transparent !important; 23 | box-shadow: none !important; 24 | width: 30px !important; 25 | padding: 0; 26 | display: flex !important; 27 | } 28 | 29 | #htmlEditor,#cssEditor,#jsEditor { 30 | position: absolute; 31 | height: 100% !important; 32 | width: 100% !important; 33 | margin: auto; 34 | top: 0;right: 0;left: 0;bottom: 0; 35 | display: none; 36 | background-color: #0E1218; 37 | } 38 | #htmlEditor { 39 | display: block; 40 | } 41 | .ace_text-layer > .ace_line { 42 | color: #fff !important; 43 | } 44 | .ace-nord-dark .ace_gutter-active-line, .ace-nord-dark .ace_marker-layer .ace_selection, .ace-nord-dark .ace_marker-layer .ace_active-line { 45 | background-color: #1A202E; 46 | } 47 | .ace-nord-dark .ace_entity.ace_name.ace_function, .ace-nord-dark .ace_meta, .ace-nord-dark .ace_support.ace_type{ 48 | color: #62B0FF !important; 49 | } 50 | .ace-nord-dark .ace_variable, .ace-nord-dark .ace_variable.ace_language{ 51 | color: rgb(255, 79, 132) !important; 52 | } 53 | .ace-nord-dark .ace_string, .ace-nord-dark .ace_constant.ace_numeric { 54 | color: #ffcc41 !important; 55 | } 56 | .ace-nord-dark .ace_support.ace_function { 57 | color: #5bdb9b !important; 58 | } 59 | .ace-nord-dark .ace_keyword { 60 | color: rgb(154, 76, 218) !important; 61 | } 62 | 63 | .swal2-popup{ 64 | background-color: #0E1218 !important; 65 | } 66 | .swal2-title { 67 | color: #62B0FF !important; 68 | font-family: 'Comfortaa', sans-serif; 69 | } 70 | .swal2-html-container{ 71 | color: #fff !important; 72 | font-family: 'Comfortaa', sans-serif; 73 | } 74 | .swal2-styled.swal2-confirm { 75 | background-color: #62B0FF !important;color: #0E1218 !important; 76 | font-family: 'Comfortaa', sans-serif; 77 | } 78 | .swal2-styled.swal2-cancel{ 79 | background-color: #FF6D6D !important;color: #fff !important; 80 | font-family: 'Comfortaa', sans-serif; 81 | } 82 | 83 | @media (min-width: 600px) { 84 | ::-webkit-scrollbar { 85 | height: 10px; 86 | width: 10px; 87 | appearance: none; 88 | background-color: #0E1218; 89 | } 90 | 91 | ::-webkit-scrollbar-thumb { 92 | appearance: none; 93 | border-radius: 10px; 94 | background-color: #1A202E; 95 | } 96 | 97 | ::-webkit-scrollbar-thumb:hover { 98 | appearance: none; 99 | border-radius: 10px; 100 | background-color: #262f44; 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 20 | 21 | 22 | 23 | 27 | 31 | 32 | 33 | 37 | 41 | 42 | 46 | 50 | 51 | 52 | 53 | 54 | 58 | 59 | 68 | Xper 69 | 70 | 71 | 72 |
73 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/pages/deploypage.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useHistory } from 'react-router-dom'; 3 | 4 | import firebase from '../components/firebase'; 5 | 6 | import { makeStyles } from '@material-ui/core/styles'; 7 | import Backdrop from '@material-ui/core/Backdrop'; 8 | import CircularProgress from '@material-ui/core/CircularProgress'; 9 | import Button from '@material-ui/core/Button'; 10 | 11 | const useStyles = makeStyles((theme) => ({ 12 | iframe: { 13 | position: 'absolute', 14 | margin: 'auto', 15 | height: '100%', 16 | width: '100%', 17 | top: '0', 18 | right: '0', 19 | left: '0', 20 | bottom: '0', 21 | outline: 0, 22 | border: 0, 23 | backgroundColor: 'white', 24 | }, 25 | seeCode: { 26 | position: 'absolute', 27 | margin: 'auto', 28 | right: 15, 29 | bottom: 15, 30 | color: "#1A202E", 31 | backgroundColor: '#50C0FF !important' 32 | } 33 | })) 34 | function Deploypage(props) { 35 | document.title = "Deploy - Xper"; 36 | 37 | let history = useHistory(); 38 | 39 | const classes = useStyles(); const iframeRef = React.useRef(); 40 | 41 | let userID = props.match.params.UID, projectID = props.match.params.projectID; 42 | 43 | const [open, setOpen] = React.useState(true); 44 | 45 | React.useEffect(() => { 46 | firebase.database().ref("WebDev/" + userID + "/" + projectID).once("value").then(snap => { 47 | if (snap.key === projectID) { 48 | var old_element = document.getElementsByClassName(classes.iframe)[0]; 49 | var new_element = old_element.cloneNode(true); 50 | old_element.parentNode.replaceChild(new_element, old_element); 51 | let output = new_element.contentWindow.document; 52 | let htmlDoc = "" + snap.val().html + ""; 53 | try { 54 | // output.contentWindow.location.reload(true); 55 | output.open(); 56 | output.write(htmlDoc); 57 | output.close(); 58 | setOpen(false); 59 | document.title = output.title + ' - Xper'; 60 | } catch (e) { 61 | //Fuck You error 62 | console.log(e) 63 | } 64 | } 65 | }).catch(error => { 66 | console.warn('Contents not found!'); 67 | history.push("/notfound") 68 | }) 69 | firebase.database().ref("WebDev/" + userID).on("child_changed", snap => { 70 | if (snap.key === projectID) { 71 | var old_element = document.getElementsByClassName(classes.iframe)[0]; 72 | var new_element = old_element.cloneNode(true); 73 | old_element.parentNode.replaceChild(new_element, old_element); 74 | let output = new_element.contentWindow.document; 75 | let htmlDoc = "" + snap.val().html + ""; 76 | try { 77 | // output.contentWindow.location.reload(true); 78 | output.open(); 79 | output.write(htmlDoc); 80 | output.close(); 81 | document.title = output.title + ' - Xper'; 82 | setOpen(false); 83 | } catch (e) { 84 | //Fuck You error 85 | console.log(e) 86 | } 87 | } 88 | }) 89 | }, []) 90 | return ( 91 |
92 | 93 | 94 | 95 |