diff --git a/.firebaserc b/.firebaserc index 4e9539f..89383e5 100644 --- a/.firebaserc +++ b/.firebaserc @@ -1,5 +1,5 @@ { "projects": { - "default": "servercrazy" + "default": "serverkrazy" } } diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml new file mode 100644 index 0000000..7737c99 --- /dev/null +++ b/.github/workflows/firebase-hosting-merge.yml @@ -0,0 +1,20 @@ +# This file was auto-generated by the Firebase CLI +# https://github.com/firebase/firebase-tools + +name: Deploy to Firebase Hosting on merge +'on': + push: + branches: + - master +jobs: + build_and_deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: npm ci && npm run build + - uses: FirebaseExtended/action-hosting-deploy@v0 + with: + repoToken: '${{ secrets.GITHUB_TOKEN }}' + firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_SERVERKRAZY }}' + channelId: live + projectId: serverkrazy diff --git a/.github/workflows/firebase-hosting-pull-request.yml b/.github/workflows/firebase-hosting-pull-request.yml new file mode 100644 index 0000000..ed74220 --- /dev/null +++ b/.github/workflows/firebase-hosting-pull-request.yml @@ -0,0 +1,17 @@ +# This file was auto-generated by the Firebase CLI +# https://github.com/firebase/firebase-tools + +name: Deploy to Firebase Hosting on PR +'on': pull_request +jobs: + build_and_preview: + if: '${{ github.event.pull_request.head.repo.full_name == github.repository }}' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: npm ci && npm run build + - uses: FirebaseExtended/action-hosting-deploy@v0 + with: + repoToken: '${{ secrets.GITHUB_TOKEN }}' + firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_SERVERKRAZY }}' + projectId: serverkrazy diff --git a/firebase.json b/firebase.json index c0f7178..022d8af 100644 --- a/firebase.json +++ b/firebase.json @@ -1,22 +1,22 @@ { "database": { - "rules": "database.rules.json" + "rules": "database.rules.json" }, "hosting": [ - { - "site": "servercrazy", - "public": "build", - "ignore": [ - "firebase.json", - "**/.*", - "**/node_modules/**" - ], - "rewrites": [ - { - "source": "**", - "destination": "/index.html" - } - ] - } + { + "site": "servercrazy", + "public": "build", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } ] -} \ No newline at end of file +} diff --git a/package-lock.json b/package-lock.json index 568e8f1..83058f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "react-router-dom": "^6.21.3", "react-scripts": "5.0.1", "react-terminal": "^1.4.4", + "sass": "^1.71.1", "web-vitals": "^2.1.4" }, "devDependencies": { @@ -12431,6 +12432,11 @@ "url": "https://opencollective.com/immer" } }, + "node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -20736,6 +20742,22 @@ "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz", "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, + "node_modules/sass": { + "version": "1.71.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", + "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/sass-loader": { "version": "12.6.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", diff --git a/package.json b/package.json index 9c076bd..c0b1b86 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "react-router-dom": "^6.21.3", "react-scripts": "5.0.1", "react-terminal": "^1.4.4", + "sass": "^1.71.1", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/src/backend.js b/src/backend.js index f2bbe11..8a02099 100644 --- a/src/backend.js +++ b/src/backend.js @@ -1,40 +1,31 @@ // import { HTMLforFile } from "./utilComponents/HTMLforFile"; // import TEMPLATEfile from "./utilComponents/TEMPLATEfile"; // import TEMPLATEmsg from "./utilComponents/TEMPLATEmsg"; +import { initializeApp } from "firebase/app"; import { - ref as refStorage, - put, - uploadBytesResumable, - getStorage, - deleteObject, - getDownloadURL, - listAll, -} from "firebase/storage"; -import { + EmailAuthProvider, + FacebookAuthProvider, + GoogleAuthProvider, createUserWithEmailAndPassword, + getAuth, getRedirectResult, - signInWithEmailAndPassword, + linkWithPopup, onAuthStateChanged, + reauthenticateWithCredential, + reauthenticateWithPopup, + reload, + sendEmailVerification, + sendPasswordResetEmail, + signInWithEmailAndPassword, signInWithPopup, signInWithRedirect, signOut, - getAuth, - updatePassword, - reauthenticateWithPopup, - updateProfile, - sendEmailVerification, - reauthenticateWithCredential, - linkWithPopup, unlink as unlinkProvider, - reload, - AuthCredential, - EmailAuthProvider, - sendPasswordResetEmail, updateEmail, + updatePassword, + updateProfile, verifyBeforeUpdateEmail, } from "firebase/auth"; -import { GoogleAuthProvider, FacebookAuthProvider } from "firebase/auth"; -import { initializeApp } from "firebase/app"; import { child, getDatabase, @@ -46,15 +37,23 @@ import { push, ref, remove, + set, update, } from "firebase/database"; import { + deleteObject, + getDownloadURL, + getStorage, + listAll, + ref as refStorage, + uploadBytesResumable, +} from "firebase/storage"; +import { + getParams, + getRandomString, getThumb, - manageErrorFireBase, log, - _, - getRandomString, - getParams, + manageErrorFireBase, timestamp, } from "./utilites.js"; let TEMPLATEfile = () => {}; @@ -253,7 +252,7 @@ class Server { console.log(data); this.server = ref(firebase.database(), this.serverName); - push(child(this.server, "serverDetails"), { + set(child(this.server, "serverDetails"), { owner: this.fbobj.currentUser.uid, ownerName: this.fbobj.currentUser.displayName, created: timestamp(), @@ -296,8 +295,10 @@ class Server { ServerDetails: child(this.server, "serverDetails"), data: child(this.server, "data"), }; - onChildAdded(child(this.server, "serverDetails"), (data) => { - this.serverOwner = data.val().owner; + onValue(child(this.server, "serverDetails"), (data) => { + if (data.exists()) { + this.serverOwner = data.val().owner; + } this.onServChange(); }); @@ -368,6 +369,10 @@ class Server { } } isMyServer = () => { + if (this.server == null) { + return false; + } + if (this.fbobj.currentUser == null) return false; return this.serverOwner == this.fbobj.currentUser.uid; }; isMine = (sender) => { diff --git a/src/components/App.jsx b/src/components/App.jsx index d4dd57e..ee73d53 100644 --- a/src/components/App.jsx +++ b/src/components/App.jsx @@ -13,6 +13,7 @@ import JumpToServer from "./JumpToServer"; import ServerInfo from "./ServerInfo"; import { TerminalContextProvider } from "react-terminal"; import { Cookies, useCookies, withCookies } from "react-cookie"; +import Loading from "./utils/Loading"; const firebaseContext = React.createContext(); const serverContext = React.createContext(); const msgBucketContext = React.createContext(); @@ -29,7 +30,7 @@ function App() { }); } const [cookies, setCookies] = useCookies(["serverName"]); - window._ = { __fb, __server, __msgBucket ,cookies}; + window._ = { __fb, __server, __msgBucket, cookies }; function setServCookie(serverName) { setCookies("serverName", serverName, { path: "/" }); } @@ -79,7 +80,7 @@ function App() { }, [server, fb, msgBucket]); return ( -
+ @@ -93,6 +94,15 @@ function App() { + + } + /> } /> } /> @@ -137,7 +147,7 @@ function App() { -
+ ); } diff --git a/src/components/Chatting_Screen/InputType/InputElement.jsx b/src/components/Chatting_Screen/InputType/InputElement/InputElement.jsx similarity index 58% rename from src/components/Chatting_Screen/InputType/InputElement.jsx rename to src/components/Chatting_Screen/InputType/InputElement/InputElement.jsx index 8adb0fb..df37f03 100644 --- a/src/components/Chatting_Screen/InputType/InputElement.jsx +++ b/src/components/Chatting_Screen/InputType/InputElement/InputElement.jsx @@ -1,21 +1,24 @@ import React, { Fragment, useState } from "react"; -import { Form } from "react-bootstrap"; +import { FloatingLabel, Form, FormControl } from "react-bootstrap"; +import { Floating_Control_Label } from "../../../utils/FormComp"; +import "./index.css" function InputElement({ msg, setMsg, handleMsgInput }) { const [isFocused, setIsFocused] = useState(false); return ( - - - - + Type a Message : <>} + id="ControlInput1" as="textarea" - placeholder="Type a message" + placeholder="" autoFocus onFocus={() => setIsFocused(true)} onBlur={() => setIsFocused(false)} onChange={(e) => setMsg(e.target.value)} value={msg} - accessKey="y" + accessKey="y" onKeyDown={(e) => { if (e.key == "Enter") { if (e.shiftKey || e.altKey) { @@ -29,7 +32,7 @@ function InputElement({ msg, setMsg, handleMsgInput }) { } }} /> - + ); } diff --git a/src/components/Chatting_Screen/InputType/InputElement/index.css b/src/components/Chatting_Screen/InputType/InputElement/index.css new file mode 100644 index 0000000..07342b5 --- /dev/null +++ b/src/components/Chatting_Screen/InputType/InputElement/index.css @@ -0,0 +1,14 @@ +.inputelement{ + .float-control-label{ + width: 100%; + .form-floating{ + label{ + color: white !important; + &:after{ + display: none + } + } + } + } + +} \ No newline at end of file diff --git a/src/components/Chatting_Screen/InputType/InputElement/index.js b/src/components/Chatting_Screen/InputType/InputElement/index.js new file mode 100644 index 0000000..ced0847 --- /dev/null +++ b/src/components/Chatting_Screen/InputType/InputElement/index.js @@ -0,0 +1,2 @@ +import InputElement from "./InputElement.jsx" +export default InputElement; diff --git a/src/components/Chatting_Screen/InputType/InputType.jsx b/src/components/Chatting_Screen/InputType/InputType.jsx deleted file mode 100644 index 199e182..0000000 --- a/src/components/Chatting_Screen/InputType/InputType.jsx +++ /dev/null @@ -1,202 +0,0 @@ -import React, { useContext, useState } from "react"; -import { Button, Form, FormGroup, FormLabel } from "react-bootstrap"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { - faCamera, - faContactBook, - faFile, - faHeadphones, - faImage, - faLocationDot, - faLocationPin, - faPaperPlane, - faPaperclip, - faSmile, - faTerminal, - faVideo, -} from "@fortawesome/free-solid-svg-icons"; -import { isMobile } from "../../../utilites"; -import InputElement from "./InputElement"; -import Terminal from "../../Terminal/Terminal"; -import { TerminalCxt } from "../../App"; - -const emojis_raw = ["😊", "😂", "🤣"]; -function givemeSet(emojis, n) { - let emojiArrays = []; - for (let i = 0; i < n; i++) { - emojiArrays.push( - emojis.sort(() => Math.random() - 0.5).slice(i * n, (i + 1) * n) - ); - } - return emojiArrays; -} -let emojiSet = givemeSet(emojis_raw, 5); -function InputType({ server, className }) { - const [msg, setMsg] = useState(""); - const [fileShareVisible, setFileShareVisible] = useState(false); - const [emojiVisible, setEmojiVisible] = useState(false); // [setEmojiVisible] - - function shareContacts() { - server.sendContacts(); - } - function shareLocation() { - server.sendLocation(msg); - } - function handleMsgInput(e) { - console.log(e); - e.preventDefault(); - if (!msg) return; - server.sendMessage(msg); - setMsg(""); - } - const terminalCxt = useContext(TerminalCxt); - - function handleFile(e) { - Array.from(e.target.files).forEach((file) => { - console.log(file); - - server.sendFile(msg, file); - }); - } - return ( -
-
- {fileShareVisible && ( -
-
- - - - - - - - -
-
- - - - - - - - - - {" "} - {isMobile() && ( - - - - - - )} - - - - - -
-
- )} - {emojiVisible && ( -
-
- {emojiSet.map((emojis) => ( -
- {emojis.map((emoji) => ( - - ))} -
- ))} -
-
- )} -
- - - {terminalCxt.isVisible ? ( - - ) : ( - - )} - - - -
-
- -
- ); -} - -export default InputType; diff --git a/src/components/Chatting_Screen/InputType/InputType/InputType.jsx b/src/components/Chatting_Screen/InputType/InputType/InputType.jsx new file mode 100644 index 0000000..43fbb5a --- /dev/null +++ b/src/components/Chatting_Screen/InputType/InputType/InputType.jsx @@ -0,0 +1,228 @@ +import React, { useContext, useEffect, useState } from "react"; +import { Button, Form, FormGroup, FormLabel } from "react-bootstrap"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { + faCamera, + faContactBook, + faFile, + faHeadphones, + faImage, + faLocationDot, + faLocationPin, + faPaperPlane, + faPaperclip, + faSmile, + faTerminal, + faVideo, +} from "@fortawesome/free-solid-svg-icons"; +import { isMobile } from "../../../../utilites"; +import InputElement from "../InputElement/InputElement"; +import Terminal from "../../../Terminal/Terminal"; +import { TerminalCxt } from "../../../App"; +import { useLocation } from "react-router-dom"; +import "./index.sass"; + +const emojis_raw = ["😊", "😂", "🤣"]; +function givemeSet(emojis, n) { + let emojiArrays = []; + const randOrder = emojis.sort(() => Math.random() - 0.5); + for (let i = 0; i < randOrder.length / n; i++) { + emojiArrays.push(randOrder.slice(i * n, (i + 1) * n)); + } + return emojiArrays; +} +let emojiSet = givemeSet(emojis_raw, 5); +window.emojiSet = emojiSet; +function InputType({ server, className }) { + const [msg, setMsg] = useState(""); + const [fileShareVisible, setFileShareVisible] = useState(false); + const [emojiVisible, setEmojiVisible] = useState(false); // [setEmojiVisible] + const location = useLocation(); + useEffect(() => { + if (location.state?.messageTyped) { + setMsg(new String(location.state.messageTyped)); + terminalCxt.setTerminalVisibility(false); + } + }, [location]); + function shareContacts() { + server.sendContacts(); + } + function shareLocation() { + server.sendLocation(msg); + } + function handleMsgInput(e) { + console.log(e); + e.preventDefault(); + if (!msg) return; + server.sendMessage(msg); + setMsg(""); + } + const terminalCxt = useContext(TerminalCxt); + + function handleFile(e) { + Array.from(e.target.files).forEach((file) => { + console.log(file); + + server.sendFile(msg, file); + }); + } + return ( +
+
+ {fileShareVisible && ( +
+
+
+ + + + + + + + +
+
+ +
+
+ + + + + + + + + + {" "} + {isMobile() && ( + + + + + + )} + + + + + +
+
+
+ )} + {emojiVisible && ( +
+
+ {emojiSet.map((emojis, index_emoji) => ( +
+ {emojis.map((emoji) => ( + + ))} +
+ ))} +
+
+ )} + {terminalCxt.isVisible ? ( + + ) : ( +
+
+ + + + + + +
+
+ )} + +
+ ); +} + +export default InputType; diff --git a/src/components/Chatting_Screen/InputType/InputType/index.js b/src/components/Chatting_Screen/InputType/InputType/index.js new file mode 100644 index 0000000..7cb6898 --- /dev/null +++ b/src/components/Chatting_Screen/InputType/InputType/index.js @@ -0,0 +1,2 @@ +import InputType from "./InputType.jsx" +export default InputType; diff --git a/src/components/Chatting_Screen/InputType/InputType/index.sass b/src/components/Chatting_Screen/InputType/InputType/index.sass new file mode 100644 index 0000000..37e6b6d --- /dev/null +++ b/src/components/Chatting_Screen/InputType/InputType/index.sass @@ -0,0 +1,73 @@ +@import "/src/css/mixin.sass" +.inputtype + .fileshare-cont + width: 100% + @include d-center + flex-direction: column + gap: 10px + .other-cont + width: 100% + @include d-center + .other + background: $glass + border-radius: 15px + padding: 10px + width: 65% + @include d-center + justify-content: space-evenly + .file-cont + width: 100% + @include d-center + .file + background: $glass + border-radius: 15px + padding: 10px + width: 75% + @include d-center + justify-content: space-evenly + + .emojis-cont + width: 100% + @include d-center + .emojis + background: $glass + padding: 20px + border-radius: 15px + width: 75% + justify-content: space-evenly + display: flex + flex-direction: column + .emoji-row + display: flex + justify-content: space-evenly + gap: 10px + .emoji + font-size: 1.5rem + .kb-input-row + padding: 3px 20px + display: flex + align-items: center + justify-content: space-evenly + @include bgglass + .emoji-btn + color: #fbd043 + .clip-btn + @include bgglass + padding: 10px + outline: 0 + border: 0 + width: 60px + height: 60px + border-radius: 50% + margin:10px 5px + + + .send-btn + @include bgglass + padding: 10px + outline: 0 + border: 0 + width: 60px + height: 60px + border-radius: 50% + margin:10px 5px diff --git a/src/components/Chatting_Screen/ServerChat.jsx b/src/components/Chatting_Screen/ServerChat.jsx index 10cc4af..f579d24 100644 --- a/src/components/Chatting_Screen/ServerChat.jsx +++ b/src/components/Chatting_Screen/ServerChat.jsx @@ -1,7 +1,7 @@ import { faTerminal } from "@fortawesome/free-solid-svg-icons"; -import React, { useContext } from "react"; +import React, { useContext, useEffect } from "react"; import { TerminalCxt, firebaseContext, msgBucketContext, serverContext } from "../App"; import { Chatting } from "./Chatting"; import { ServerInfoHeading } from "./ServerInfoHeading"; @@ -10,6 +10,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Button } from "react-bootstrap"; import { _delete, _fileDelete } from "../../backend"; import InputType from "./InputType"; +import { useLocation, useNavigate, useParams } from "react-router-dom"; function ServerChat() { // { firebase, server, msgBucket } @@ -17,15 +18,30 @@ function ServerChat() { const server = useContext(serverContext); const msgBucket = useContext(msgBucketContext); const terminalCxt = useContext(TerminalCxt); + const navigate = useNavigate(); + function handleDelete(key) { _delete(server.serverName, key); } function handleFileDelete(filePath, key) { _fileDelete(filePath, server.serverName, key); } + const params = useParams(); + useEffect(()=>{ + if(params.server){ + if(server.server ==null){ + navigate("/jump/"+params.server,{ + state:{ + continue__:"/server/"+params.server+"/chat", + isReloaded:true + } + }) + } + } + },[params]) return (
-
+
e)} - className="w-100 overflow-auto" + className="w-100 h-100 overflow-auto align-items-end d-center " _delete={handleDelete} _fileDelete={handleFileDelete} downloadURL={server.downloadURL} /> -
+
{terminalCxt.isVisible ||( - + )}
diff --git a/src/components/Home.jsx b/src/components/Home.jsx deleted file mode 100644 index 5387093..0000000 --- a/src/components/Home.jsx +++ /dev/null @@ -1,129 +0,0 @@ -import { - faEdit, - faSignOut, - faTerminal, -} from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import React, { useContext, useEffect, useState } from "react"; -import { Button, Card } from "react-bootstrap"; -import { Link, useLocation, useNavigate } from "react-router-dom"; -import { TerminalCxt, firebaseContext, serverContext } from "./App"; -import Terminal from "./Terminal/Terminal"; -import { To_chat } from "./utils/Navigations"; -function Home() { - const firebase = useContext(firebaseContext); - const server = useContext(serverContext); - const location = useLocation(); - const terminalCxt = useContext(TerminalCxt); - function setTerminalVisibility(e) { - terminalCxt.setTerminalVisibility(e); - } - useEffect(() => { - if (location.state?.serverToBeCreated == true) { - createServer(); - } - }, [location]); - - const navigate = useNavigate(); - function signOut() { - firebase.signout(); - } - function handleNotAuthed() { - navigate("/auth/login", { - state: { continue__: "/", serverToBeCreated: true }, - }); - } - function createServer() { - console.log("creating server"); - if (!server.server) { - server.createServer( - () => { - handleNotAuthed(); - }, - (e) => navigate("/server/" + e) - ); - } - console.log("server created" + server.serverName); - } - function handleStop() { - server.stopServer(() => navigate("/")); - } - function handleExit() { - server.exitServer(() => navigate("/")); - } - return ( - <> -
- - -
-
Hi,
-
- {firebase?.currentUser?.displayName} -
-
-
-
- -
- -
{" "} - - -
-
-
-
- {server.server ? ( -
-
{server.serverName}
- {server.isMyServer() ? ( - - ) : ( - - )} - - -
- ) : ( -
- - - Jump to Server - -
- )} - {terminalCxt.isVisible ? ( - "} /> - ) : ( - - )} -
- - ); -} - -export default Home; diff --git a/src/components/Home/Home.jsx b/src/components/Home/Home.jsx new file mode 100644 index 0000000..d56b151 --- /dev/null +++ b/src/components/Home/Home.jsx @@ -0,0 +1,140 @@ +import { + faEdit, + faSignOut, + faTerminal, +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import React, { useContext, useEffect, useState } from "react"; +import { button, Card } from "react-bootstrap"; +import { Link, useLocation, useNavigate } from "react-router-dom"; +import { TerminalCxt, firebaseContext, serverContext } from "../App"; +import Terminal from "../Terminal/Terminal"; +import { To_chat } from "../utils/Navigations"; +import "./index.sass"; + +function Home() { + const firebase = useContext(firebaseContext); + const server = useContext(serverContext); + const location = useLocation(); + const terminalCxt = useContext(TerminalCxt); + function setTerminalVisibility(e) { + terminalCxt.setTerminalVisibility(e); + } + useEffect(() => { + if (location.state?.serverToBeCreated == true) { + createServer(); + } + }, [location]); + + const navigate = useNavigate(); + function signOut() { + firebase.signout(); + } + function handleNotAuthed() { + navigate("/auth/login", { + state: { continue__: "/", serverToBeCreated: true }, + }); + } + function createServer() { + console.log("creating server"); + if (!server.server) { + server.createServer( + () => { + handleNotAuthed(); + }, + (e) => navigate("/server/" + e) + ); + } + console.log("server created" + server.serverName); + } + function handleStop() { + server.stopServer(() => navigate("/")); + } + function handleExit() { + server.exitServer(() => navigate("/")); + } + return ( +
+ + +
+
Hi,
+
+ {firebase?.currentUser?.displayName} +
+
+
+
+ +
+ +
{" "} + + +
+
+
+
+ {server.server ? ( +
+
{server.serverName}
+ {server.isMyServer() ? ( + + ) : ( + + )} + + +
+ ) : ( +
+ + + Jump to Server + +
+ )} + {terminalCxt.isVisible ? ( + "} /> + ) : ( + + )} +
+ ); +} + +export default Home; diff --git a/src/components/Home/index.js b/src/components/Home/index.js new file mode 100644 index 0000000..f00a217 --- /dev/null +++ b/src/components/Home/index.js @@ -0,0 +1,2 @@ +import Home from "./Home.jsx" +export default Home; diff --git a/src/components/Home/index.sass b/src/components/Home/index.sass new file mode 100644 index 0000000..dd6d7c1 --- /dev/null +++ b/src/components/Home/index.sass @@ -0,0 +1,4 @@ +@import "/src/css/mixin.sass" +.home + .bg-glass + @include bgglass diff --git a/src/components/JumpToServer.jsx b/src/components/JumpToServer.jsx index b8a5ff7..523d02d 100644 --- a/src/components/JumpToServer.jsx +++ b/src/components/JumpToServer.jsx @@ -3,18 +3,25 @@ import { Button, Form } from "react-bootstrap"; import { useLocation, useNavigate, useParams } from "react-router-dom"; import { Back } from "./utils/Navigations"; import QRScan from "./utils/QRScan"; -import { serverContext } from "./App"; +import { firebaseContext, serverContext } from "./App"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCheck } from "@fortawesome/free-solid-svg-icons"; +import Loading from "./utils/Loading"; function JumpToServer() { const server = useContext(serverContext); const params_server_url = useParams()["server"]; const [serverName, setServerName] = useState(""); + const [showInterface, setShowInterface] = useState(false); + const firebase = useContext(firebaseContext); const navigate = useNavigate(); - + const location = useLocation(); + useEffect(() => { + if (location.state?.isReloaded) setShowInterface(false); + else setShowInterface(true); + }, [location]); function handleNotAuthed(s_name) { navigate("/auth/login", { - state: { continue__: "/jump/" + s_name }, + state: { ...location.state, continue__: "/jump/" + s_name }, }); } @@ -28,14 +35,19 @@ function JumpToServer() { function tryServer(sname, ifNotFound = function () {}) { let s_name = validateServerName(sname); if (isValidServerName(s_name)) - server.jumpToServer( - s_name, - () => handleNotAuthed(s_name), - (e) => { - if (e) navigate("/server/" + s_name + "/chat"); - else ifNotFound(); - } - ); + if (firebase.currentUser) + server.jumpToServer( + s_name, + () => handleNotAuthed(s_name), + (e) => { + if (e) { + if (location.state?.continue__) { + console.log("continue__", location.state.continue__); + navigate(location.state.continue__); + } else navigate("/server/" + s_name + "/chat"); + } else ifNotFound(); + } + ); } function validateServerName(e) { let s_name = e; @@ -53,45 +65,56 @@ function JumpToServer() { tryServer(serverName); } return ( -
+
- { - setServerName(validateServerName(e)); // console.log(e); - tryServer(validateServerName(e)); - }} - style={{ width: "40vmin", height: "40vmin" }} - /> -
- - Server Name -
- - setServerName( - e.target.value.replaceAll(/[^a-zA-Z0-9]/gi, "").toLowerCase() - ) - } - autoComplete="off" - required - maxLength={8} - minLength={8} - /> - -
-
- -
+ {showInterface ? ( + <> + { + setServerName(validateServerName(e)); // console.log(e); + tryServer(validateServerName(e)); + }} + style={{ width: "40vmin", height: "40vmin" }} + /> +
+ + Server Name +
+ + setServerName( + e.target.value + .replaceAll(/[^a-zA-Z0-9]/gi, "") + .toLowerCase() + ) + } + autoComplete="off" + required + maxLength={8} + minLength={8} + className={ + isValidServerName(serverName) ? "is-valid" : "is-invalid" + } + /> + +
+
+ +
+ + ) : ( +
+ +
+ )}
); diff --git a/src/components/ServerInfo.jsx b/src/components/ServerInfo.jsx index 0df9a85..ef9b365 100644 --- a/src/components/ServerInfo.jsx +++ b/src/components/ServerInfo.jsx @@ -6,20 +6,34 @@ import { faTerminal, } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import React, { useContext } from "react"; +import React, { useContext, useEffect } from "react"; import { Button } from "react-bootstrap"; -import { Link, useNavigate } from "react-router-dom"; +import { Link, useNavigate, useParams } from "react-router-dom"; import { Back, To_chat } from "./utils/Navigations"; import { TerminalCxt, serverContext } from "./App"; import Terminal from "./Terminal/Terminal"; -import {shareServer }from "./utils/js/utils"; +import { shareServer } from "./utils/js/utils"; function ServerInfo() { const server = useContext(serverContext); const terminalCxt = useContext(TerminalCxt); + const navigate = useNavigate(); + const params = useParams(); + useEffect(() => { + if (params.server) { + if (server.server == null) { + navigate("/jump/" + params.server, { + state: { + continue__: "/server/" + params.server, + isReloaded: true, + }, + }); + } + } + }, [params]); + function setTerminalVisibility(e) { terminalCxt.setTerminalVisibility(e); } - const navigate = useNavigate(); function stopServer() { server.stopServer(() => navigate("/")); } @@ -27,70 +41,68 @@ function ServerInfo() { server.exitServer(() => navigate("/")); } return ( -
-
+
+
-
+
server_qr
-
{server.serverName}
-
+
+ {server.serverName} +
+
{server.isMyServer() ? ( - + ) : ( - + )}
-
- - +
- {terminalCxt.isVisible ? ( - "} /> - ) : ( - - )} +
+ {terminalCxt.isVisible ? ( + "} /> + ) : ( + + )} +
); - - } export default ServerInfo; diff --git a/src/components/Terminal/SmallCommands.js b/src/components/Terminal/SmallCommands.js index 2e60013..fc8f052 100644 --- a/src/components/Terminal/SmallCommands.js +++ b/src/components/Terminal/SmallCommands.js @@ -15,5 +15,6 @@ const smallCommands = { }, do: _do, exec: _do, + eval: _do, }; export default smallCommands; diff --git a/src/components/Terminal/Terminal.jsx b/src/components/Terminal/Terminal.jsx index a273039..f40ddd2 100644 --- a/src/components/Terminal/Terminal.jsx +++ b/src/components/Terminal/Terminal.jsx @@ -172,6 +172,13 @@ function Terminal({ close = function () {}, prompt }) { shareThis(); } + function type() { + let x = smallCommands.do(...arguments) + if(x=="[Object Object]")return "object"; + navigate("/server/" + server.serverName + "/chat", { + state: { messageTyped:new String(x) }, + }); + } const commands__ = { clear: () => { console.log("clearing"); @@ -210,6 +217,10 @@ function Terminal({ close = function () {}, prompt }) { }, ...{ send: send, + say: send, + echo:e=>e, + ["chat.type"]: type, + type: type, ["chat.send"]: send, ["chat.send.location"]: send_location, send_location: send_location, diff --git a/src/components/utils/FormComp/FormComp.jsx b/src/components/utils/FormComp/FormComp.jsx index cd38f98..790fdb7 100644 --- a/src/components/utils/FormComp/FormComp.jsx +++ b/src/components/utils/FormComp/FormComp.jsx @@ -17,12 +17,13 @@ function Floating_Control_Label({ value, onChange, autoComplete, + ...props }) { return (
@@ -36,6 +37,7 @@ function Floating_Password_Label({ autoComplete = "current-password", value, onChange, + ...props }) { const [show, setShow] = useState(false); return ( @@ -46,7 +48,7 @@ function Floating_Password_Label({ diff --git a/src/components/utils/Loading.jsx b/src/components/utils/Loading.jsx index 76fc0d8..fa6c92f 100644 --- a/src/components/utils/Loading.jsx +++ b/src/components/utils/Loading.jsx @@ -1,9 +1,18 @@ -import React from 'react' +import { faSpinner } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import React from "react"; -function Loading() { +function Loading({ className = "", size = "2x",loadingText="Loading" }) { return ( -
Loading
- ) +
+ +
+ + +
+
{loadingText}
+
+ ); } -export default Loading \ No newline at end of file +export default Loading; diff --git a/src/components/utils/Navigations.jsx b/src/components/utils/Navigations.jsx index fa29289..b0980e3 100644 --- a/src/components/utils/Navigations.jsx +++ b/src/components/utils/Navigations.jsx @@ -11,10 +11,10 @@ function Back({className , to = ".."}) {
); } -function To_chat({ serverName }) { +function To_chat({ serverName,size="3x" }) { return ( - - + + ); } diff --git a/src/css/bs.css b/src/css/bs.css new file mode 100644 index 0000000..14946a6 --- /dev/null +++ b/src/css/bs.css @@ -0,0 +1,48 @@ + +img{ + user-select: none; +} +.flex-center{ + display: flex; + justify-content: center; + align-items: center; +} + +.outline-0{ + outline: 0 !important; +} +.w-fit-content{ + width: fit-content; +} +.h-fit-content{ + height:fit-content; +} +.w-85{ + width: 85%; +} +.h-85{ + height: 85%; +} +.start-75{ + left: 75%; +} +.d-center{ + display: flex; + justify-content: center; + align-items: center; +} +.bg-yellow{ + background-color: yellow !important;; +} +.text-yellow{ + color: yellow !important; +} +.after-bg-transparent::after{ + background-color: transparent !important; +} +.box-shadow-none{ + box-shadow: none !important; +} +.resize-none{ + resize: none !important; +} \ No newline at end of file diff --git a/src/css/index.css b/src/css/index.css index 7f4ce02..219ed9b 100644 --- a/src/css/index.css +++ b/src/css/index.css @@ -1,136 +1,118 @@ -@import url('https://fonts.googleapis.com/css2?family=Dosis:wght@500&family=Syne:wght@400;500;600;700;800&display=swap'); - +@import url("https://fonts.googleapis.com/css2?family=Dosis:wght@500&family=Syne:wght@400;500;600;700;800&display=swap"); +@import url("bs.css"); :root { - - --themeColorLight: #bbf54c; - --themeColorDark: #5c3c98; - --glass:#fff4; - --blur:5px; + --themeColorLight: #bbf54c; + --themeColorDark: #5c3c98; + --glass: #fff4; + --blur: 5px; } @font-face { - font-family: JetBrains Mono; - src: url("/src/assets/fonts/JetBrainsMono-Regular.woff2"); + font-family: JetBrains Mono; + src: url("/src/assets/fonts/JetBrainsMono-Regular.woff2"); } @font-face { - font-family: Neue Machina; - src: url("/src/assets/fonts/Neue-Machina.woff"); -} -img{ - user-select: none; -} -.flex-center{ - display: flex; - justify-content: center; - align-items: center; -} - -.outline-0{ - outline: 0 !important; -} -.w-fit-content{ - width: fit-content; -} -.h-fit-content{ - height:fit-content; + font-family: Neue Machina; + src: url("/src/assets/fonts/Neue-Machina.woff"); } -.w-85{ - width: 85%; -} -.h-85{ - height: 85%; -} -.start-75{ - left: 75%; -} - body { - margin: 0; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - --bs-body-font-family: 'Syne', monospace !important; - --themeColor: var(--themeColorLight); + margin: 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + --bs-body-font-family: "Syne", monospace !important; + --themeColor: var(--themeColorLight); } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; } #root { - width: 100vw; - height: 100vh; - overflow: hidden; + width: 100vw; + height: 100vh; + overflow: hidden; } nav.navbar { - background: linear-gradient(180deg, var(--themeColor), transparent, var(--bs-body-bg)), linear-gradient(90deg, var(--themeColor), var(--bs-body-bg)) !important; + background: linear-gradient( + 180deg, + var(--themeColor), + transparent, + var(--bs-body-bg) + ), + linear-gradient(90deg, var(--themeColor), var(--bs-body-bg)) !important; } .footer { - background: linear-gradient(0deg, var(--themeColor), transparent, var(--bs-body-bg)), linear-gradient(-90deg, var(--themeColor), var(--bs-body-bg)) !important; - + background: linear-gradient( + 0deg, + var(--themeColor), + transparent, + var(--bs-body-bg) + ), + linear-gradient(-90deg, var(--themeColor), var(--bs-body-bg)) !important; } .navbar-collapse.collapse { - display: flex; - flex-direction: column; + display: flex; + flex-direction: column; } -@media (min-width:576px) { - .navbar-expand-sm .navbar-collapse { - display: flex; - flex-direction: row !important; - } +@media (min-width: 576px) { + .navbar-expand-sm .navbar-collapse { + display: flex; + flex-direction: row !important; + } } -body[data-bs-theme=dark] { - --themeColor: var(--themeColorDark) +body[data-bs-theme="dark"] { + --themeColor: var(--themeColorDark); } .flex-0 { - flex: 0 0 auto !important; + flex: 0 0 auto !important; } .text-currentcolor { - color: currentColor !important + color: currentColor !important; } .code404 { - font-family: 'dosis', monospace !important; - font-size: 10em; + font-family: "dosis", monospace !important; + font-size: 10em; } @keyframes rotateR { - 0% { - transform: rotate(0deg); - } + 0% { + transform: rotate(0deg); + } - 100% { - transform: rotate(359deg); - } + 100% { + transform: rotate(359deg); + } } -.no-underline{ - text-decoration: none; +.no-underline { + text-decoration: none; } -.gears-anim{ - transform: scale(.5); +.gears-anim { + transform: scale(0.5); } -.code404>span { - position: relative; - display: inline-block; +.code404 > span { + position: relative; + display: inline-block; } -.streamImg{ - max-height: 50vh; - max-width: 87vw; +.streamImg { + max-height: 50vh; + max-width: 87vw; } .code404 span:nth-child(1) span { - animation: fa-fade 1.5s 0s infinite; + animation: fa-fade 1.5s 0s infinite; } .code404 span:nth-child(2) span { - animation: fa-fade 1.5s .5s infinite; + animation: fa-fade 1.5s 0.5s infinite; } .code404 span:nth-child(3) span { - animation: fa-fade 1.5s 1s infinite; -} \ No newline at end of file + animation: fa-fade 1.5s 1s infinite; +} diff --git a/src/css/mixin.sass b/src/css/mixin.sass new file mode 100644 index 0000000..79246e3 --- /dev/null +++ b/src/css/mixin.sass @@ -0,0 +1,11 @@ +$glass:#fff4 +$blur:4px +@mixin bgglass + background-color: $glass !important + backdrop-filter: blur($blur) !important + border-radius: 20px + +@mixin d-center + display: flex + align-items: center + justify-content: center \ No newline at end of file