Skip to content

Commit f4b2499

Browse files
authored
Merge pull request #208 from ctfguide-tech/dev
sync learn up
2 parents aa6c10a + 17a4d8f commit f4b2499

23 files changed

+749
-165
lines changed

public/darkLogocrop.png

13.7 KB
Loading

public/site.png

20.3 KB
Loading

src/components/Footer.jsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ export function Footer() {
1515
<NavLink href="../privacy-policy">Privacy Policy</NavLink>
1616
<NavLink href="https://status.ctfguide.com/">Status</NavLink>
1717
<NavLink href="../careers">Careers</NavLink>
18+
1819
</div>
20+
21+
1922
</nav>
2023
</div>
2124
<div className="mx-auto flex max-w-4xl flex-col items-center border-t border-slate-400/10 py-10 sm:flex-row-reverse sm:justify-between">
@@ -74,7 +77,7 @@ export function Footer() {
7477
</Link>
7578
</div>
7679
<p className="mt-6 text-sm text-white sm:mt-0">
77-
Copyright &copy; {new Date().getFullYear()} CTFGuide. All rights
80+
Copyright &copy; {new Date().getFullYear()} CTFGuide Corporation. All rights
7881
reserved. <br></br>
7982
</p>
8083
</div>

src/components/Header.jsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,11 @@ export function Header() {
9292
<nav className="relative z-50 flex justify-between">
9393
<div className="flex items-center md:gap-x-12">
9494
<Link href="../" aria-label="Home">
95-
<Logo className="h-10 w-auto" />
95+
<Logo className="h-10 w-auto" />
9696
</Link>
97+
9798
</div>
99+
98100
<div className="flex items-center gap-x-5 md:gap-x-8">
99101
<div>
100102
<NavLink className="text-white" href="/login">

src/components/home/GP.jsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export default function GP() {
6767
<h2 className="text-base font-semibold leading-7 text-blue-600">CTFGuide Practice Range</h2>
6868
<p className="mt-2 text-3xl font-bold tracking-tight text-white sm:text-4xl">Never run out of practice material.</p>
6969
<p className="mt-6 text-lg leading-8 text-white">
70-
Access hundreds of challenges, writeups, and dynamic labs to help you improve your skills and prepare for competitions.
70+
Access community uploaded challenges, writeups, and dynamic labs to help you improve your skills and prepare for competitions.
7171
</p>
7272
</div>
7373
</div>
@@ -78,7 +78,7 @@ className="mx-auto max-w-7xl px-6 lg:px-8">
7878
<img
7979
src="../site.png"
8080
alt="App screenshot"
81-
className="animate__animated animate__backInUp mb-[-12%] rounded-xl shadow-2xl ring-1 ring-neutral-800 pt-4"
81+
className="animate__animated animate__backInUp mb-[-12%] rounded-xl shadow-2xl ring-1 ring-neutral-800"
8282
width={2432}
8383

8484
height={1442}

src/components/home/Hero.jsx

+121-12
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { useState } from 'react'
2-
import { Dialog } from '@headlessui/react'
3-
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
1+
import { useState, useEffect } from 'react'
2+
import { Dialog, Popover, Transition } from '@headlessui/react'
3+
import { Bars3Icon, XMarkIcon, ChevronDownIcon, AcademicCapIcon, BuildingOfficeIcon } from '@heroicons/react/24/outline'
44
import TextLoop from "react-text-loop";
55
import Link from 'next/link'
66
import { Logo } from '@/components/Logo'
77
import Banner from '@/components/home/Banner';
8-
8+
import request from '@/utils/request';
99

1010
const navigation = [
1111

@@ -15,7 +15,29 @@ const navigation = [
1515

1616
export function Hero() {
1717
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
18+
const [visibleCards, setVisibleCards] = useState(0)
19+
const [activityFeed, setActivityFeed] = useState([])
20+
21+
useEffect(() => {
22+
const fetchActivityFeed = async () => {
23+
24+
// use mock data if api is down
25+
setActivityFeed([
26+
{ userName: 'laphatize', challengeName: 'Excel-lently Hidden', profilePic: 'https://imagedelivery.net/1Dym4oPRvM_5USnDWCdSCw/7523c0cb-2330-443c-94f1-030cd8bde300/public' },
27+
{ userName: 'herronjo', challengeName: 'Trading Bananas' , profilePic: 'https://imagedelivery.net/1Dym4oPRvM_5USnDWCdSCw/1bd03d05-1057-48fc-3d3f-b3ed512cb500/public' },
28+
{ userName: 'thunderbird', challengeName: 'Sneaky Cat ' , profilePic: 'https://imagedelivery.net/1Dym4oPRvM_5USnDWCdSCw/3b312b5f-c90d-490d-80d0-e52b367d4400/public' },
29+
{ userName: 'stevestef', challengeName: 'Pretty Obvious', profilePic: 'https://imagedelivery.net/1Dym4oPRvM_5USnDWCdSCw/3e75c7a3-dfe9-47cc-0d46-736187e62400/public' },
30+
]);
31+
};
32+
33+
fetchActivityFeed();
1834

35+
const timer = setInterval(() => {
36+
setVisibleCards((prev) => (prev < activityFeed.length ? prev + 1 : prev))
37+
}, 1000) // Adjust timing as needed
38+
39+
return () => clearInterval(timer)
40+
}, [activityFeed.length])
1941

2042
return (
2143
<div className="bg-neutral-900">
@@ -27,6 +49,59 @@ export function Hero() {
2749
<Link href="../" aria-label="Home">
2850
<Logo className="h-10 w-auto" />
2951
</Link>
52+
53+
</div>
54+
<div className="flex items-center gap-x-5 md:gap-x-8 hidden sm:flex">
55+
<Popover className="relative">
56+
{({ open }) => (
57+
<>
58+
<Popover.Button className="flex items-center gap-x-1 text-white focus:outline-none">
59+
Solutions
60+
<ChevronDownIcon className={`${open ? 'transform rotate-180' : ''} h-5 w-5 transition-transform duration-150 ease-in-out`} />
61+
</Popover.Button>
62+
<Transition
63+
enter="transition duration-100 ease-out"
64+
enterFrom="transform scale-95 opacity-0"
65+
enterTo="transform scale-100 opacity-100"
66+
leave="transition duration-75 ease-out"
67+
leaveFrom="transform scale-100 opacity-100"
68+
leaveTo="transform scale-95 opacity-0"
69+
>
70+
<Popover.Panel className="absolute left-1/2 z-10 mt-3 w-screen max-w-md -translate-x-1/2 transform px-2 sm:px-0">
71+
<div className="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5">
72+
<div className="relative grid gap-6 bg-neutral-900 bg-blend-overlay px-5 py-6 sm:gap-8 sm:p-8">
73+
<Link href="/education" className="block p-3 -m-3 transition duration-150 ease-in-out rounded-md hover:bg-neutral-800">
74+
<div className="flex items-start">
75+
<AcademicCapIcon className="h-8 w-8 text-blue-500 mr-3 mt-1" />
76+
<div>
77+
<p className="text-base font-medium text-white pb-1"><span className='font-semibold'>CTFGuide</span> Education</p>
78+
<p className="text-sm text-white">A platform for learning and training cybersecurity skills in the classroom.</p>
79+
</div>
80+
</div>
81+
</Link>
82+
<div className="block p-3 -m-3 transition duration-150 ease-in-out rounded-md hover:bg-neutral-800">
83+
<div className="flex items-start">
84+
<BuildingOfficeIcon className="h-6 w-6 text-blue-500 mr-3 mt-1" />
85+
<div className="flex-grow">
86+
<div className="text-base font-medium text-white flex justify-between items-center">
87+
<span><span className='font-semibold'>CTFGuide</span> Enterprise</span>
88+
<span className='text-xs text-white bg-blue-800 px-2 rounded-full'>Coming Soon</span>
89+
</div>
90+
<p className="text-sm text-white">Train your team to defend against real-world threats.</p>
91+
</div>
92+
</div>
93+
</div>
94+
</div>
95+
</div>
96+
</Popover.Panel>
97+
</Transition>
98+
</>
99+
)}
100+
</Popover>
101+
<Link href="/careers" className="text-white">
102+
Company
103+
</Link>
104+
30105
</div>
31106
<div className="flex lg:hidden">
32107
<button
@@ -112,22 +187,31 @@ export function Hero() {
112187
}}
113188
/>
114189
</div>
115-
<div className="py-24 sm:py-32 lg:pb-40">
190+
<div className="py-24 sm:py-24 lg:pb-40">
116191
<div className="mx-auto max-w-7xl px-6 lg:px-8">
117-
<div className= " animate__animated animate__fadeInUp mx-auto max-w-4xl text-center">
118-
<h1 className="text-4xl font-bold tracking-normal text-white sm:text-6xl leading-relaxed ">
192+
<div className= " animate__animated animate__fadeInUp mx-auto max-w-6xl text-left">
193+
<div className='grid sm:grid-cols-6 grid-cols-1'>
194+
<div className='col-span-4 '>
195+
<h1 className="text-4xl font-normal tracking-normal text-white sm:text-4xl leading-relaxed ">
196+
197+
<div className="mt-10 mb-2 text-3xl text-white sm:text-2xl flex items-center justify-left">
198+
<img className=" w-8 text-center ml-0 mr-2 " src="../../../../darkLogocrop.png" />
199+
200+
<h1 className='text-3xl font-normal m'> <span className="text-white font-semibold"> CTFGuide </span>
201+
</h1>
202+
</div>
119203
The platform that <span className="text-blue-600 leading-relaxed">
120204
<TextLoop>
121205
<span>grows</span>
122206
<span>develops</span>
123207
<span>trains</span>
124208
</TextLoop>
125-
</span> <span className='mt-3'> cybersecurity talent.</span>
209+
</span> <br></br><span className='mt-3'> cybersecurity talent.</span>
126210
</h1>
127211
<p className="mt-6 text-lg leading-8 text-gray-300">
128-
A data-driven simulation platform that provides a realistic, hands-on experience for you to become a cybersecurity professional.
212+
The social learning platform for all things cybersecurity.
129213
</p>
130-
<div className="mt-10 flex items-center justify-center gap-x-6">
214+
<div className="mt-10 flex items-center gap-x-6">
131215
<a
132216
href="../register"
133217
className="rounded-md px-6 py-1.5 text-lg font-semibold text-white border border-white hover:bg-white hover:text-black focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-400"
@@ -137,7 +221,32 @@ export function Hero() {
137221
<p onClick={() => window.scrollTo(0, 1500)} className="cursor-pointer text-lg font-semibold leading-6 text-white">
138222
Learn more <span aria-hidden="true"></span>
139223
</p>
224+
</div>
140225
</div>
226+
227+
<div className='col-span-2 mt-10 hidden sm:block'>
228+
<div className="space-y-2">
229+
{activityFeed.slice(0, visibleCards).map((card, index) => (
230+
<div
231+
key={card.userName}
232+
className='hover:bg-neutral-700 duration-300 bg-neutral-800 cursor-pointer p-4 rounded-lg flex items-center transform transition-all ease-in-out'
233+
style={{
234+
opacity: 0,
235+
animation: `fadeInUp 0.5s ease-out ${index * 0.2}s forwards`,
236+
}}
237+
>
238+
<img src={card.profilePic ? card.profilePic : `https://robohash.org/${card.userName}`} className='w-12 h-12 rounded-full mr-4' alt={card.userName} />
239+
<div>
240+
<p className='text-white font-bold'>{card.userName}</p>
241+
<p className='text-gray-400 text-sm'>
242+
solved <span className='text-yellow-400'>{card.challengeName}</span>
243+
</p>
244+
</div>
245+
</div>
246+
))}
247+
</div>
248+
</div>
249+
</div>
141250
</div>
142251
<img
143252

@@ -148,7 +257,7 @@ export function Hero() {
148257
autoPlay
149258
width={2432}
150259
height={1442}
151-
className="animate__animated animate__fadeInUp mt-16 rounded-md bg-white/5 shadow-2xl ring-1 ring-white/10 sm:mt-24"
260+
className="animate__animated animate__fadeInUp mt-16 rounded-md bg-white/5 shadow-2xl ring-1 ring-white/10 sm:mt-28"
152261

153262
>
154263
<source src="../sample_vid.mp4" type="video/mp4" />
@@ -171,4 +280,4 @@ export function Hero() {
171280
</div>
172281
</div>
173282
);
174-
}
283+
}

src/components/home/SecondaryFeatures.jsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -296,14 +296,14 @@ export function SecondaryFeatures() {
296296
<section
297297
id="secondary-features"
298298
aria-label="Features for simplifying everyday business tasks"
299-
className="pb-14 pt-20 sm:pb-20 sm:pt-32 lg:pb-32"
299+
className="pb-14 pt-20 sm:pb-20 sm:pt-32 lg:pb-32 "
300300
>
301301
<Container>
302302
<div className="mx-auto max-w-6xl md:text-center">
303-
<h2 className="text-base font-semibold leading-7 text-blue-600">CTFGuide Education</h2>
303+
<h2 className="text-base font-semibold leading-7 text-blue-600 hidden">CTFGuide for K-12 and Universities</h2>
304304

305305
<h2 className="font-display text-3xl tracking-tight text-white sm:text-4xl">
306-
We're the best platform for teaching cybersecurity.
306+
An all-in-one platform for teaching cybersecurity.
307307
</h2>
308308

309309
</div>

src/components/practice/community.jsx

+43-33
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import ChallengeCard from '../profile/ChallengeCard';
33
import { Fragment } from 'react';
44
import { Listbox, Transition } from '@headlessui/react';
55
import { CheckIcon, ChevronUpDownIcon } from '@heroicons/react/24/solid';
6-
6+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
7+
import { faFolderOpen } from '@fortawesome/free-solid-svg-icons';
78
function getCategoryIcon(category) {
89
switch (category.toLowerCase()) {
910
case 'forensics':
@@ -290,39 +291,48 @@ export function Community({ challenges }) {
290291
</div>
291292
</div>
292293
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4 mt-6">
293-
{challenges && (results.length > 0 ? results : challenges)
294-
.filter((challenge) => {
295-
if (
296-
difficulty.toLowerCase() !== 'all' &&
297-
challenge.difficulty.toLowerCase() !== difficulty.toLowerCase()
298-
) {
299-
return false;
300-
}
301-
if (
302-
filter !== '' &&
303-
challenge.category.includes(filter.toLowerCase())
304-
) {
294+
{results.length > 0 ? (
295+
results
296+
.filter((challenge) => {
297+
if (
298+
difficulty.toLowerCase() !== 'all' &&
299+
challenge.difficulty.toLowerCase() !== difficulty.toLowerCase()
300+
) {
301+
return false;
302+
}
303+
if (
304+
filter !== '' &&
305+
challenge.category.includes(filter.toLowerCase())
306+
) {
307+
return true;
308+
}
309+
if (
310+
filter !== '' &&
311+
!(
312+
challenge.title
313+
.toLowerCase()
314+
.includes(filter.toLowerCase()) ||
315+
challenge.content
316+
.toLowerCase()
317+
.includes(filter.toLowerCase())
318+
)
319+
) {
320+
return false;
321+
}
305322
return true;
306-
}
307-
if (
308-
filter !== '' &&
309-
!(
310-
challenge.title
311-
.toLowerCase()
312-
.includes(filter.toLowerCase()) ||
313-
challenge.content
314-
.toLowerCase()
315-
.includes(filter.toLowerCase())
316-
)
317-
) {
318-
return false;
319-
}
320-
return true;
321-
})
322-
.map((challenge) => (
323-
<ChallengeCard challenge={challenge} key={challenge.challengeId} />
324-
))
325-
}
323+
})
324+
.map((challenge) => (
325+
<ChallengeCard challenge={challenge} key={challenge.challengeId} />
326+
))
327+
) : (
328+
// kinda hacky but it works
329+
challenges.length != 0 && (
330+
<div className="bg-neutral-800/50 p-4 py-10 rounded-md w-full col-span-4 text-center">
331+
<FontAwesomeIcon icon={faFolderOpen} className="w-10 h-10 mx-auto mb-4 text-neutral-400" />
332+
<p className="text-white">No challenges found with the current filters. Try changing the filters or search for a different challenge.</p>
333+
</div>
334+
)
335+
)}
326336
</div>
327337
</div>
328338
</>

src/components/settingComponents/generalPage.jsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Skeleton from 'react-loading-skeleton';
1111
import 'react-loading-skeleton/dist/skeleton.css';
1212
import { ToastContainer, toast } from 'react-toastify';
1313
import 'react-toastify/dist/ReactToastify.css';
14-
import Markdown from 'react-markdown';
14+
import { MarkdownViewer } from '@/components/MarkdownViewer';
1515
import { Context } from '@/context';
1616
import { useContext } from 'react';
1717
import { CheckIcon } from '@heroicons/react/20/solid';
@@ -691,7 +691,7 @@ export default function General() {
691691
Bio Preview
692692
</label>
693693
<div className="mt-2 rounded-lg bg-neutral-800 p-4 text-white">
694-
<Markdown>{tempBio}</Markdown>
694+
<MarkdownViewer content={tempBio}></MarkdownViewer>
695695
</div>
696696
</div>
697697
)}

src/middleware.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ export function middleware(req) {
2525
}
2626

2727
export const config = {
28-
matcher: ['/((?!_next/static|favicon.ico|login|careers|register|onboarding|forgot-password|userrs|privacy-policy|404|terms-of-service|learn|$).*)'],
28+
matcher: ['/((?!_next/static|favicon.ico|login|careers|register|onboarding|forgot-password|education|userrs|privacy-policy|404|terms-of-service|learn|$).*)'],
2929
}

0 commit comments

Comments
 (0)