diff --git a/.env.development b/.env.development index ce0b2196..7b4ac54c 100644 --- a/.env.development +++ b/.env.development @@ -23,7 +23,7 @@ NEXT_PUBLIC_APP_STORAGE_BUCKET=ctfguide-dev.appspot.com NEXT_PUBLIC_APP_MESSAGING_SENDER_ID=792987058367 NEXT_PUBLIC_APP_ID=1:792987058367:web:c48935325e46043c3cc60a NEXT_PUBLIC_APP_MEASUREMENT_ID=G-7ZNKM9VFN2 -NEXT_PUBLIC_TERM_URL=https://dev-terminal-api.ctfguide.com/ +NEXT_PUBLIC_TERM_URL=https://prod-terminal-api.ctfguide.com/ NEXT_PUBLIC_APP_STRIPE_KEY=pk_test_51MAliSF4qMywXyoUvCPG6HDRQaRy4ach2pfDIj4sklm4k22VinqVcygs61F7UWosnZo6Ig1iFykui6rsbR0tRStm00LRZCrXQ8 diff --git a/package.json b/package.json index b6526b72..b2867c26 100644 --- a/package.json +++ b/package.json @@ -65,9 +65,11 @@ "react-markdown": "^9.0.1", "react-markdown-editor-lite": "^1.3.4", "react-resizable": "^3.0.5", + "react-responsive": "^10.0.0", "react-router-dom": "^6.9.0", "react-select-country-list": "^2.2.3", "react-simplemde-editor": "^5.2.0", + "react-swipeable": "^7.0.1", "react-text-loop": "^2.3.0", "react-text-transition": "^3.1.0", "react-toastify": "^10.0.5", diff --git a/src/components/StandardNav.jsx b/src/components/StandardNav.jsx index 186916de..f8f87590 100644 --- a/src/components/StandardNav.jsx +++ b/src/components/StandardNav.jsx @@ -1,4 +1,4 @@ -import { Fragment, useEffect, useState } from 'react'; +import { Fragment, useEffect, useState, useRef } from 'react'; import { Disclosure, Menu, Popover, Transition } from '@headlessui/react'; import { Dialog } from '@headlessui/react'; @@ -218,6 +218,21 @@ export function StandardNav({ guestAllowed, alignCenter = true }) { : 'text-gray-300 hover:text-gray-50 border-transparent' }`; + const panelRef = useRef(null); + + useEffect(() => { + const handleClickOutside = (event) => { + if (panelRef.current && !panelRef.current.contains(event.target)) { + setOpen(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [panelRef]); + return ( <> {isPopoverOpen && ( @@ -242,16 +257,16 @@ export function StandardNav({ guestAllowed, alignCenter = true }) {
{/* Mobile menu button */} - + Open main menu {open ? (
- -
- {/* Current: "bg-blue-50 border-blue-500 text-blue-700", Default: "border-transparent text-gray-300 hover:text-white" */} - - Dashboard - - - Learn - - - Classes - - - Practice - - - Live - -
-
-
+ + +
+ {/* Current: "bg-blue-50 border-blue-500 text-blue-700", Default: "border-transparent text-gray-300 hover:text-white" */} - Profile + Dashboard - Settings + Practice + + + Leaderboards - - Sign out + Classes
-
- +
+
+ + + + + + + +
+
+
+
+
setShowSearchModal(true)} + > + + Search for anything +
+
+
+ + )} diff --git a/src/components/dashboard/DashboardHeader.jsx b/src/components/dashboard/DashboardHeader.jsx index 2bd6e369..e8cdfb46 100644 --- a/src/components/dashboard/DashboardHeader.jsx +++ b/src/components/dashboard/DashboardHeader.jsx @@ -90,17 +90,17 @@ export function DashboardHeader() { backgroundImage: 'url("https://images.unsplash.com/photo-1633259584604-afdc243122ea?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1770&q=80")', }} - className="h-20 w-full object-cover lg:h-20" + className="h-20 w-full object-cover lg:h-20 " alt="" >
-
-
-
+
+
+
{(pfp && ( @@ -116,8 +116,8 @@ export function DashboardHeader() {
-
-

+
+
{username || ( - Developer + + + Developer )} {role === 'PRO' && ( - - Pro + + + Pro )} -

-

+

+

{' '} {location || (

-
-
-

- {username || ( - - )} -

-
+
); -} +} \ No newline at end of file diff --git a/src/pages/challenges/[...id].jsx b/src/pages/challenges/[...id].jsx index ead03f25..29a94e52 100644 --- a/src/pages/challenges/[...id].jsx +++ b/src/pages/challenges/[...id].jsx @@ -26,6 +26,8 @@ import WriteupModal from '@/components/WriteupModal'; export default function Challenge() { const router = useRouter(); const [selectedWriteup, setSelectedWriteup] = useState(null); + const [isTerminalFullscreen, setIsTerminalFullscreen] = useState(false); + const [isChallengeFullscreen, setIsChallengeFullscreen] = useState(true); // I hate this const [urlChallengeId, urlSelectedTab, urlWriteupId] = (router ?? {})?.query?.id ?? [undefined, undefined, undefined]; @@ -313,27 +315,123 @@ export default function Challenge() { -
+
-
-
-
- {Object.entries(tabs).map(([url, tab]) => )} +
+ {isChallengeFullscreen && ( +
+
+ {Object.entries(tabs).map(([url, tab]) => ( + + ))} +
+ {selectedWriteup ? ( + setSelectedWriteup(null)} writeup={selectedWriteup} /> + ) : ( + + )} +
+
+
+ + +
+
+
- {selectedWriteup ? ( - setSelectedWriteup(null)} writeup={selectedWriteup} /> - ) : ( - - )} -
-
-
- - -
+ )} + {!isChallengeFullscreen && ( +
+
+
+ {foundTerminal && ( +
+

+ Username: {userName} + +

+

+ Password: {password} + +

+

+ Remaining Time: {formatTime(minutesRemaining)} + window.open(terminalUrl, '_blank')} className="cursor-pointer hover:text-yellow-500 ml-2 fas fa-expand text-white"> + {showMessage && ( + + Sometimes browsers block iframes, try opening the terminal in full screen if it the terminal is empty. + + + )} +

+
+ )} + {fetchingTerminal ? ( +
+
+

+ {loadingMessage} +

If you see a black screen, please wait a few seconds and refresh the page.

+
+
+ ) : ( + isTerminalBooted ? ( +