Compare commits

..

66 commits

Author SHA1 Message Date
28b3f8a0b0 Fixed answer buttons
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-02 12:58:56 +03:00
6367c690a4 Fixed answer buttons
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-02 12:07:02 +03:00
2f6981f4f6 redid some changes
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-02 12:04:45 +03:00
089d1c8f14 Updated the 'about us' page
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-02 12:01:41 +03:00
kali
1e767da34c Updated spacing and some text 2024-06-02 12:01:24 +03:00
kali
6839343269 Updated spacing and some text 2024-06-02 11:58:56 +03:00
d0fe776b68 redid some changes
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>

untangled some nasty merge conflicts
2024-06-02 11:48:44 +03:00
6761a2b0d0 Updated animations (#11)
Co-authored-by: Alex Stan <alex.stan.2010@proton.me>
Co-committed-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-02 11:47:22 +03:00
5500da1f6d merged
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-02 11:42:25 +03:00
kali
10da00708a Commented landing page 2024-06-02 11:33:41 +03:00
92f0d25cd0 Added comments to |sessionconfig|
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-02 11:32:00 +03:00
kali
bcb098218b Commented about-us page 2024-06-02 11:26:28 +03:00
b7b1fca1bc Updated animations 2024-06-02 10:43:45 +03:00
kali
62b44acbdf Made the background static and updated spacing 2024-06-02 10:42:05 +03:00
5adfd1ffc1 fixed results screen sending you to /learn/sessionconfig
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-02 10:36:07 +03:00
kali
10b3e4e71c Redid undone changes durring merge errors 2024-06-02 10:28:47 +03:00
6741f0de18 fixed answer button
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-02 10:27:18 +03:00
kali
e8b8e5b800 Added licence button in about us page 2024-06-02 10:17:10 +03:00
e9ee6c0b69 Smoothed out the animations (#10)
Co-authored-by: Alex Stan <alex.stan.2010@proton.me>
Co-committed-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-02 10:10:16 +03:00
kali
0066c9f343 Fixed merge errors 2024-06-02 09:56:00 +03:00
3d1ba5cfce removed annoying icon on topic card
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-02 09:48:18 +03:00
6fa4bf8bdd Added animations 2024-06-02 09:46:38 +03:00
28eeb31054 Fixed the duplicated logo in the results page 2024-06-02 09:25:02 +03:00
7dd3d263e9 Fixed API url 2024-06-02 09:22:56 +03:00
ba0b31d0d2 Fixed the duplicated buttons 2024-06-02 09:22:27 +03:00
Ioan Chelaru Cristian
f042f07cf9 fixed the db
Signed-off-by: Ioan Chelaru Cristian <iccjoc@localhost.localdomain>
2024-06-02 01:24:20 +03:00
Ioan Chelaru Cristian
64e1aa295a removed the ip address
Signed-off-by: Ioan Chelaru Cristian <iccjoc@localhost.localdomain>
2024-06-02 01:21:06 +03:00
Ioan Chelaru Cristian
9e07238ddc Changed API url and Alex's picture
Signed-off-by: Ioan Chelaru Cristian <iccjoc@localhost.localdomain>
2024-06-02 01:09:56 +03:00
Ioan Chelaru Cristian
a3dc222184 Fixed a dumb error
Signed-off-by: Ioan Chelaru Cristian <iccjoc@localhost.localdomain>
2024-06-02 01:06:38 +03:00
Ioan Chelaru Cristian
b4fed6e3c9 Fixed quiz buttons
Signed-off-by: Ioan Chelaru Cristian <iccjoc@localhost.localdomain>

fixed merge conflicts
2024-06-02 01:02:10 +03:00
af2c5afa95 fixed a build error
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 23:58:11 +03:00
0d4d1f0944 change eslintrc
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 23:49:14 +03:00
c71f5cd9a6 polish app
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 23:42:20 +03:00
328b304b6c fixed some more merge errors
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 21:47:32 +03:00
dcd44670df fixed some merge errors
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 21:45:14 +03:00
1c6c5327c3 made the quiz functional
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>

Fixed merge conflicts
2024-06-01 21:41:34 +03:00
Ioan Chelaru Cristian
48efcce544 Fixed source code button
Signed-off-by: Ioan Chelaru Cristian <iccjoc@localhost.localdomain>
2024-06-01 20:59:42 +03:00
Ioan Chelaru Cristian
6557cfba89 Added a LOT of icons.
Signed-off-by: Ioan Chelaru Cristian <iccjoc@localhost.localdomain>

f
2024-06-01 20:30:57 +03:00
2bf3ae95a2 Modified README.md
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-01 18:17:38 +03:00
1c4aa2f744 Added a scuffed source code button
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-01 18:03:25 +03:00
a433af3f81 Updated database
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-01 17:54:31 +03:00
kali
04e0168ea0 Made spacing the same across all pages 2024-06-01 17:53:43 +03:00
kali
2743ce75d5 Made spacing the same across all pages
fixed merge conflict
2024-06-01 17:51:05 +03:00
a072d2f04c updated dynamic learning page
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 17:42:52 +03:00
kali
ee5ccde234 Updated learn directory 2024-06-01 17:41:47 +03:00
47e47d0cb4 Added the results screen
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-01 17:41:19 +03:00
43db39291e added a dynamic category page
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 17:40:03 +03:00
kali
3b362da028 Updated about us page 2024-06-01 17:33:13 +03:00
kali
2851e60c78 Updated about us page 2024-06-01 17:11:32 +03:00
kali
1fbc541a5d Alighned logo on all pages 2024-06-01 17:08:03 +03:00
b17f45c459 Added the small tab text
Signed-off-by: Ioan Cristian CHELARU <iccjoc@proton.me>
2024-06-01 17:05:13 +03:00
fffda90529 changed the topic card, the form and .gitignore (#9)
Co-authored-by: Alex Stan <alex.stan.2010@proton.me>
Co-committed-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 16:57:47 +03:00
kali
effc06eb0f Added first version of about us page 2024-06-01 16:28:54 +03:00
7d76207057 split the logo into a separate component (#8)
Co-authored-by: Alex Stan <alex.stan.2010@proton.me>
Co-committed-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 16:24:36 +03:00
3282da41ed Made the logo a link
Signed-off-by: Alex Stan <alex.stan.2010@proton.me>

fixed a merge conflict
2024-06-01 16:18:35 +03:00
kali
42baa432ad Added visual elements to make background more pleasurable 2024-06-01 16:12:33 +03:00
kali
58aa8a09c6 added logo to quiz page 2024-06-01 16:00:51 +03:00
fb25c8477c Moved a file (#7)
Co-authored-by: Alex Stan <alex.stan.2010@proton.me>
Co-committed-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 15:58:56 +03:00
kali
2530acdcf1 Added quiz page template
fixed merge conflict
2024-06-01 15:53:24 +03:00
4a98209021 Added a TopicCard component (#6) 2024-06-01 15:47:53 +03:00
kali
fda1fae418 Beutified landing page, added session select page and made it look even better 2024-06-01 15:09:01 +03:00
kali
4895d3b889 Merge branch 'uitest'
merge
2024-06-01 14:35:37 +03:00
kali
ff81a070cf Beutified landing page, added session select page and made it look good 2024-06-01 14:30:10 +03:00
819760817e Fix the API port conflict and improve docs (#3)
Co-authored-by: Alex Stan <alex.stan.2010@proton.me>
Co-committed-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 11:13:52 +03:00
8281d66939 Get posts from API (#2)
Co-authored-by: Alex Stan <alex.stan.2010@proton.me>
Co-committed-by: Alex Stan <alex.stan.2010@proton.me>
2024-06-01 11:08:49 +03:00
c76d1b3635 initapiserver-flashcards (#1)
Added api questiosn in a db.json file

Co-authored-by: kali <kali@0day.0day.com>
Reviewed-on: #1
2024-06-01 11:08:26 +03:00
35 changed files with 1789 additions and 248 deletions

View file

@ -1,3 +1,7 @@
{ {
"extends": "next/core-web-vitals" "extends": "next/core-web-vitals",
"rules": {
"react/no-unescaped-entities": "off",
"react/jsx-key": "off"
}
} }

1
.gitignore vendored
View file

@ -34,3 +34,4 @@ yarn-error.log*
# typescript # typescript
*.tsbuildinfo *.tsbuildinfo
next-env.d.ts next-env.d.ts
app/test/*

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
v20.12.2

View file

@ -1,36 +1,10 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). # ***FlashLearn***
> The React based app with flashcards for you to learn. Made for the INFOMATRIX 2024 Hackathon.
## Getting Started **How to use:**
1. **Click the "Get Started" Button.**
2. **Select a subject.**
3. ***Learn!***
First, run the development server: *Made with the MIT Licence*
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

View file

@ -1,3 +1,6 @@
`json-server db.json` # Start the server:
`json-server db.json -p 4000`
# Question endpoint:
`http://localhost:3000/questions` `http://localhost:3000/questions`
# Example:
`http://localhost:3000/questions/1` `http://localhost:3000/questions/1`

View file

@ -1,75 +1,705 @@
{ {
"questions": [ "questions": [
{ {
"id": "1", "id": 1,
"category": "C++", "category": "cpp",
"type": "quiz", "type": "none",
"question": "What is the output of the following code: std::cout << sizeof(int);", "text": "What is the output of the expression 3 + 2 * 5 in C++?",
"answer": "The output depends on the system, typically 4 on most systems." "answer": "13"
}, },
{ {
"id": "2", "id": 2,
"category": "geography", "category": "cpp",
"type": "quiz", "type": "none",
"question": "What is the capital of France?", "text": "What is the default access specifier for class members in C++?",
"answer": "Paris" "answer": "private"
}, },
{ {
"id": "3", "id": 3,
"category": "cybersecurity", "category": "cpp",
"type": "true or false", "type": "none",
"question": "A firewall can protect a network from all types of cyber attacks.", "text": "What is the name of the process that automatically converts a primitive type to its corresponding wrapper class object in C++?",
"answer": "false" "answer": "Boxing"
}, },
{ {
"id": "4", "id": 4,
"category": "C++", "category": "cpp",
"type": "true or false", "type": "none",
"question": "C++ supports multiple inheritance.", "text": "Which C++ feature allows the creation of a function or an operator with more than one form?",
"answer": "true" "answer": "Polymorphism"
}, },
{ {
"id": "5", "id": 5,
"category": "geography", "category": "cpp",
"type": "quiz", "type": "none",
"question": "Which is the largest continent by land area?", "text": "What is the main purpose of a constructor in C++?",
"answer": "Asia" "answer": "To initialize an object"
}, },
{ {
"id": "6", "id": 6,
"category": "cybersecurity", "category": "cpp",
"type": "quiz", "type": "none",
"question": "What does the acronym 'DDoS' stand for?", "text": "What does STL stand for in C++?",
"answer": "Standard Template Library"
},
{
"id": 7,
"category": "cpp",
"type": "none",
"text": "Which operator is used to access the members of a structure through a pointer in C++?",
"answer": "->"
},
{
"id": 8,
"category": "cpp",
"type": "none",
"text": "What is the keyword used to define a constant in C++?",
"answer": "const"
},
{
"id": 9,
"category": "cpp",
"type": "none",
"text": "What is the primary purpose of the 'new' operator in C++?",
"answer": "To allocate memory dynamically"
},
{
"id": 10,
"category": "cpp",
"type": "none",
"text": "What does RTTI stand for in C++?",
"answer": "Run-Time Type Information"
},
{
"id": 11,
"category": "cpp",
"type": "none",
"text": "What is a pure virtual function in C++?",
"answer": "A function with no definition that must be overridden in derived classes"
},
{
"id": 12,
"category": "cpp",
"type": "none",
"text": "What is the name of the feature that allows the same function name to be used for different types in C++?",
"answer": "Function Overloading"
},
{
"id": 13,
"category": "cpp",
"type": "none",
"text": "What is a 'namespace' in C++?",
"answer": "A declarative region that provides a scope to the identifiers inside it"
},
{
"id": 14,
"category": "cpp",
"type": "none",
"text": "Which C++ keyword is used to prevent a variable from being modified?",
"answer": "const"
},
{
"id": 15,
"category": "cpp",
"type": "none",
"text": "What is the function of the 'friend' keyword in C++?",
"answer": "To allow a function or another class access to the private and protected members of a class"
},
{
"id": 16,
"category": "cpp",
"type": "none",
"text": "What is 'inheritance' in C++?",
"answer": "The process by which one class acquires the properties and functionalities of another class"
},
{
"id": 17,
"category": "cpp",
"type": "none",
"text": "Which operator is used for scope resolution in C++?",
"answer": "::"
},
{
"id": 18,
"category": "cpp",
"type": "none",
"text": "What is a 'destructor' in C++?",
"answer": "A special member function that is executed when an object of its class is destroyed"
},
{
"id": 19,
"category": "cpp",
"type": "none",
"text": "What is the primary use of the 'this' pointer in C++?",
"answer": "To refer to the calling object itself"
},
{
"id": 20,
"category": "cpp",
"type": "none",
"text": "What is the return type of the main function in C++?",
"answer": "int"
},
{
"id": 21,
"category": "cybersec",
"type": "none",
"text": "What does 'phishing' mean in cybersecurity?",
"answer": "A technique used to trick users into providing sensitive information by pretending to be a trustworthy entity"
},
{
"id": 22,
"category": "cybersec",
"type": "none",
"text": "What is the purpose of a firewall in network security?",
"answer": "To monitor and control incoming and outgoing network traffic based on predetermined security rules"
},
{
"id": 23,
"category": "cybersec",
"type": "none",
"text": "What does 'DDoS' stand for?",
"answer": "Distributed Denial of Service" "answer": "Distributed Denial of Service"
}, },
{ {
"id": "7", "id": 24,
"category": "C++", "category": "cybersec",
"type": "quiz", "type": "none",
"question": "Which C++ standard introduced the concept of 'auto' keyword?", "text": "What is a 'zero-day' exploit?",
"answer": "C++11" "answer": "A cyber attack that occurs on the same day a vulnerability is discovered and before a fix is implemented"
}, },
{ {
"id": "8", "id": 25,
"category": "cybersec",
"type": "none",
"text": "What is 'encryption' in the context of cybersecurity?",
"answer": "The process of converting information or data into a code to prevent unauthorized access"
},
{
"id": 26,
"category": "cybersec",
"type": "none",
"text": "What does 'VPN' stand for in cybersecurity?",
"answer": "Virtual Private Network"
},
{
"id": 27,
"category": "cybersec",
"type": "none",
"text": "What is a 'trojan horse' in cybersecurity?",
"answer": "A type of malware that disguises itself as legitimate software"
},
{
"id": 28,
"category": "cybersec",
"type": "none",
"text": "What is the primary goal of social engineering attacks?",
"answer": "To manipulate individuals into divulging confidential information"
},
{
"id": 29,
"category": "cybersec",
"type": "none",
"text": "What is 'ransomware'?",
"answer": "A type of malware that encrypts a user's data and demands payment to restore access"
},
{
"id": 30,
"category": "cybersec",
"type": "none",
"text": "What does 'SQL injection' exploit?",
"answer": "Vulnerabilities in an application's software by inserting malicious SQL code"
},
{
"id": 31,
"category": "cybersec",
"type": "none",
"text": "What is 'two-factor authentication'?",
"answer": "A security process that requires two different forms of identification to access an account"
},
{
"id": 32,
"category": "cybersec",
"type": "none",
"text": "What is 'malware'?",
"answer": "Software designed to disrupt, damage, or gain unauthorized access to computer systems"
},
{
"id": 33,
"category": "cybersec",
"type": "none",
"text": "What does 'TLS' stand for in cybersecurity?",
"answer": "Transport Layer Security"
},
{
"id": 34,
"category": "cybersec",
"type": "none",
"text": "What is 'brute force attack' in cybersecurity?",
"answer": "A method to find passwords or encryption keys by trying every possible combination"
},
{
"id": 35,
"category": "cybersec",
"type": "none",
"text": "What is the primary function of an Intrusion Detection System (IDS)?",
"answer": "To monitor network traffic for suspicious activity and potential threats"
},
{
"id": 36,
"category": "cybersec",
"type": "none",
"text": "What is 'spoofing' in cybersecurity?",
"answer": "The act of disguising a communication from an unknown source as being from a known, trusted source"
},
{
"id": 37,
"category": "cybersec",
"type": "none",
"text": "What is 'rootkit'?",
"answer": "A type of malicious software designed to hide the existence of certain processes or programs from normal methods of detection"
},
{
"id": 38,
"category": "cybersec",
"type": "none",
"text": "What does 'CVE' stand for in cybersecurity?",
"answer": "Common Vulnerabilities and Exposures"
},
{
"id": 39,
"category": "cybersec",
"type": "none",
"text": "What is 'pharming' in cybersecurity?",
"answer": "A cyber attack intended to redirect a website's traffic to another, fake site"
},
{
"id": 40,
"category": "cybersec",
"type": "none",
"text": "What does 'APT' stand for in cybersecurity?",
"answer": "Advanced Persistent Threat"
},
{
"id": 41,
"category": "cybersec",
"type": "none",
"text": "What is 'cross-site scripting' (XSS)?",
"answer": "A vulnerability that allows attackers to inject malicious scripts into webpages viewed by users"
},
{
"id": 42,
"category": "cybersec",
"type": "none",
"text": "What does 'BYOD' stand for in cybersecurity?",
"answer": "Bring Your Own Device"
},
{
"id": 43,
"category": "cybersec",
"type": "none",
"text": "What is 'penetration testing'?",
"answer": "A method of evaluating the security of a computer system by simulating an attack"
},
{
"id": 44,
"category": "cybersec",
"type": "none",
"text": "What does 'CIA' stand for in cybersecurity?",
"answer": "Confidentiality, Integrity, and Availability"
},
{
"id": 45,
"category": "cybersec",
"type": "none",
"text": "What is 'smishing'?",
"answer": "A type of phishing attack that uses SMS messages to lure victims"
},
{
"id": 46,
"category": "cybersec",
"type": "none",
"text": "What is a 'honeypot' in cybersecurity?",
"answer": "A security system set up to attract and detect hackers"
},
{
"id": 47,
"category": "cybersec",
"type": "none",
"text": "What is the purpose of 'endpoint protection'?",
"answer": "To secure endpoints or entry points of end-user devices such as desktops, laptops, and mobile devices"
},
{
"id": 48,
"category": "cybersec",
"type": "none",
"text": "What does 'SIEM' stand for in cybersecurity?",
"answer": "Security Information and Event Management"
},
{
"id": 49,
"category": "cybersec",
"type": "none",
"text": "What is a 'man-in-the-middle' attack?",
"answer": "A cyber attack where the attacker secretly intercepts and relays messages between two parties"
},
{
"id": 50,
"category": "cybersec",
"type": "none",
"text": "What is 'data exfiltration'?",
"answer": "The unauthorized transfer of data from a computer"
},
{
"id": 51,
"category": "geography", "category": "geography",
"type": "true or false", "type": "none",
"question": "The Amazon River is the longest river in the world.", "text": "What is the longest river in the world?",
"answer": "false" "answer": "The Nile River"
}, },
{ {
"id": "9", "id": 52,
"category": "cybersecurity", "category": "geography",
"type": "quiz", "type": "none",
"question": "What is the main purpose of encryption?", "text": "What is the capital city of Australia?",
"answer": "To protect data confidentiality by converting it into a code." "answer": "Canberra"
}, },
{ {
"id": "10", "id": 53,
"category": "C++", "category": "geography",
"type": "quiz", "type": "none",
"question": "What is the function of the 'virtual' keyword in C++?", "text": "Which desert is the largest in the world?",
"answer": "It allows a member function to be overridden in a derived class." "answer": "The Sahara Desert"
},
{
"id": 54,
"category": "geography",
"type": "none",
"text": "What is the smallest country in the world by land area?",
"answer": "Vatican City"
},
{
"id": 55,
"category": "geography",
"type": "none",
"text": "What mountain range forms the natural border between France and Spain?",
"answer": "The Pyrenees"
},
{
"id": 56,
"category": "geography",
"type": "none",
"text": "Which country has the most natural lakes?",
"answer": "Canada"
},
{
"id": 57,
"category": "geography",
"type": "none",
"text": "What is the highest mountain in Africa?",
"answer": "Mount Kilimanjaro"
},
{
"id": 58,
"category": "geography",
"type": "none",
"text": "What is the capital of Japan?",
"answer": "Tokyo"
},
{
"id": 59,
"category": "geography",
"type": "none",
"text": "What river runs through the Grand Canyon?",
"answer": "The Colorado River"
},
{
"id": 60,
"category": "geography",
"type": "none",
"text": "Which country is known as the Land of the Rising Sun?",
"answer": "Japan"
},
{
"id": 61,
"category": "geography",
"type": "none",
"text": "What is the largest island in the world?",
"answer": "Greenland"
},
{
"id": 62,
"category": "geography",
"type": "none",
"text": "Which European country shares borders with the most neighbors?",
"answer": "Germany"
},
{
"id": 63,
"category": "geography",
"type": "none",
"text": "What is the deepest ocean trench in the world?",
"answer": "The Mariana Trench"
},
{
"id": 64,
"category": "geography",
"type": "none",
"text": "Which U.S. state is the largest by area?",
"answer": "Alaska"
},
{
"id": 65,
"category": "geography",
"type": "none",
"text": "What is the capital city of Canada?",
"answer": "Ottawa"
},
{
"id": 66,
"category": "geography",
"type": "none",
"text": "Which river is the longest in Europe?",
"answer": "The Volga River"
},
{
"id": 67,
"category": "geography",
"type": "none",
"text": "Which continent has the most countries?",
"answer": "Africa"
},
{
"id": 68,
"category": "geography",
"type": "none",
"text": "What is the capital of Brazil?",
"answer": "Brasília"
},
{
"id": 69,
"category": "geography",
"type": "none",
"text": "What is the official language of Egypt?",
"answer": "Arabic"
},
{
"id": 70,
"category": "geography",
"type": "none",
"text": "Which ocean is the largest by surface area?",
"answer": "The Pacific Ocean"
},
{
"id": 71,
"category": "geography",
"type": "none",
"text": "What is the name of the sea bordered by Europe to the north and Africa to the south?",
"answer": "The Mediterranean Sea"
},
{
"id": 72,
"category": "geography",
"type": "none",
"text": "Which country has the most islands?",
"answer": "Sweden"
},
{
"id": 73,
"category": "geography",
"type": "none",
"text": "What is the largest country in South America?",
"answer": "Brazil"
},
{
"id": 74,
"category": "geography",
"type": "none",
"text": "What is the longest mountain range in the world?",
"answer": "The Andes"
},
{
"id": 75,
"category": "geography",
"type": "none",
"text": "What is the capital city of Russia?",
"answer": "Moscow"
},
{
"id": 76,
"category": "geography",
"type": "none",
"text": "What is the largest desert in Asia?",
"answer": "The Gobi Desert"
},
{
"id": 77,
"category": "geography",
"type": "none",
"text": "What is the capital of Kenya?",
"answer": "Nairobi"
},
{
"id": 78,
"category": "geography",
"type": "none",
"text": "Which country is the smallest in Europe by land area?",
"answer": "Vatican City"
},
{
"id": 79,
"category": "geography",
"type": "none",
"text": "Which river forms part of the border between Mexico and the United States?",
"answer": "The Rio Grande"
},
{
"id": 80,
"category": "geography",
"type": "none",
"text": "What is the capital city of South Korea?",
"answer": "Seoul"
},
{
"id": 81,
"category": "geography",
"type": "none",
"text": "What is the largest country in Africa by land area?",
"answer": "Algeria"
},
{
"id": 82,
"category": "geography",
"type": "none",
"text": "Which country is known as the Land of the Maple Leaf?",
"answer": "Canada"
},
{
"id": 83,
"category": "geography",
"type": "none",
"text": "Which river is the longest in Asia?",
"answer": "The Yangtze River"
},
{
"id": 84,
"category": "geography",
"type": "none",
"text": "What is the capital city of India?",
"answer": "New Delhi"
},
{
"id": 85,
"category": "geography",
"type": "none",
"text": "Which ocean lies on the east coast of the United States?",
"answer": "The Atlantic Ocean"
},
{
"id": 86,
"category": "geography",
"type": "none",
"text": "What is the capital city of Italy?",
"answer": "Rome"
},
{
"id": 87,
"category": "geography",
"type": "none",
"text": "Which river is the main river that flows through Paris?",
"answer": "The Seine"
},
{
"id": 88,
"category": "geography",
"type": "none",
"text": "What is the smallest ocean in the world?",
"answer": "The Arctic Ocean"
},
{
"id": 89,
"category": "geography",
"type": "none",
"text": "What is the capital city of Mexico?",
"answer": "Mexico City"
},
{
"id": 90,
"category": "geography",
"type": "none",
"text": "Which country is known for its unique wildlife and has the Great Barrier Reef?",
"answer": "Australia"
},
{
"id": 91,
"category": "geography",
"type": "none",
"text": "What is the capital of Argentina?",
"answer": "Buenos Aires"
},
{
"id": 92,
"category": "geography",
"type": "none",
"text": "Which country has the largest population in the world?",
"answer": "China"
},
{
"id": 93,
"category": "geography",
"type": "none",
"text": "What is the capital city of the United Kingdom?",
"answer": "London"
},
{
"id": 94,
"category": "geography",
"type": "none",
"text": "Which continent is known as the birthplace of humanity?",
"answer": "Africa"
},
{
"id": 95,
"category": "geography",
"type": "none",
"text": "What is the capital city of Thailand?",
"answer": "Bangkok"
},
{
"id": 96,
"category": "geography",
"type": "none",
"text": "What is the capital of Egypt?",
"answer": "Cairo"
},
{
"id": 97,
"category": "geography",
"type": "none",
"text": "Which country is home to the Amazon Rainforest?",
"answer": "Brazil"
},
{
"id": 98,
"category": "geography",
"type": "none",
"text": "What is the capital city of Spain?",
"answer": "Madrid"
},
{
"id": 99,
"category": "geography",
"type": "none",
"text": "What is the currency of Japan?",
"answer": "Yen"
},
{
"id": 100,
"category": "geography",
"type": "none",
"text": "Which country is known as the Land of Fire and Ice?",
"answer": "Iceland"
} }
] ],
"sessions": []
} }

110
app/about-us/page.tsx Normal file
View file

@ -0,0 +1,110 @@
import { ClipboardDocumentListIcon, DocumentTextIcon } from '@heroicons/react/24/outline';
import Logo from '../components/logo';
import TopicCard from '../components/topic_card';
import LinkButton from '../components/link-button';
{/*Index of people and their respective image and title*/}
const people = [
{
name: 'Andrei Banu',
role: 'UI/UX designer',
imageUrl:
'arch.png',
email: 'mailto:child1.andy@gmail.com'
},
{
name: 'Ioan Cristian Chelaru',
role: 'UI/UX designer',
imageUrl:
'blahaj.avif',
email: 'mailto:iccjoc@proton.me'
},
{
name: 'Alexandru Gabriel Stan',
role: 'Backend & UI developer',
imageUrl:
'alex.png',
email: 'mailto:alex.stan.2010@proton.me'
},
// More people...
]
export default function Example() {
return (
<div className="sm:py-32">
{/*Background visuals*/}
<div
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
aria-hidden="true"
>
<div
className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
<div
className="relative left-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%+36rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
</div>
<Logo/>
<div style={{paddingBottom: '100px'}}></div>
<div className="mx-auto grid max-w-7xl gap-x-8 gap-y-20 px-6 lg:px-8 xl:grid-cols-3"> {/*Team presentation text*/}
<div className="max-w-2xl">
<h2 className="text-3xl font-bold tracking-tight text-gray-200 sm:text-4xl">Meet our developers</h2>
<p className="mt-6 text-lg leading-8 text-gray-200">
We are a group of passionate middle schoolers that got together to hopefully make a difference in the world
</p>
</div>
{/*Display people*/}
<ul role="list" className="grid gap-x-8 gap-y-12 sm:grid-cols-2 sm:gap-y-16 xl:col-span-2">
{people.map((person) => (
<li key={person.name}>
<div className="flex items-center gap-x-6">
<img className="h-16 w-16 rounded-full" src={person.imageUrl} alt="" />
<div>
<h3 className="text-base font-semibold leading-7 tracking-tight text-gray-200">{person.name}</h3>
<p className="text-sm font-semibold leading-6 text-indigo-200">{person.role}</p>
<LinkButton text="Send mail" href={person.email}/>
</div>
</div>
</li>
))}
</ul>
</div>
<br></br>
{/*Licence and source code buttons*/}
<div
style={{display:"flex", alignItems: 'center', alignSelf:'center', justifyContent: 'center', marginLeft: "40px", marginRight: "40px"}}
>
<a
href="https://git.gra.phite.ro/BlahajTeam/next-app"
className="rounded-md text-sm font-semibold text-gray-200 shadow-sm hover:text-gray-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{minWidth: '190px', maxWidth: '190px', paddingLeft: '50px', paddingRight: '50px', paddingTop: '20px', paddingBottom: '20px', alignSelf: 'center'}}
>
<DocumentTextIcon></DocumentTextIcon>
Source Code
</a>
<a
href="https://git.gra.phite.ro/BlahajTeam/next-app/src/branch/main/LICENSE"
className="rounded-md text-sm font-semibold text-gray-200 shadow-sm hover:text-gray-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{minWidth: '190px', maxWidth: '190px', paddingLeft: '50px', paddingRight: '50px', paddingTop: '20px', paddingBottom: '20px', alignSelf: 'center'}}
>
<ClipboardDocumentListIcon></ClipboardDocumentListIcon>
Our Licence
</a>
</div>
<div
className="absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]"
aria-hidden="true"
>
</div>
</div>
)
}

View file

@ -1,24 +0,0 @@
import Image from "next/image";
export default function Home() {
return (
<main className="grid min-h-full place-items-center bg-white px-6 py-24 sm:py-32 lg:px-8">
<div className="text-center">
<p className="text-base font-semibold text-indigo-600">404</p>
<h1 className="mt-4 text-3xl font-bold tracking-tight text-gray-900 sm:text-5xl">Page not found</h1>
<p className="mt-6 text-base leading-7 text-gray-600">Sorry, we couldnt find the page youre looking for.</p>
<div className="mt-10 flex items-center justify-center gap-x-6">
<a
href="#"
className="rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
Go back home
</a>
<a href="#" className="text-sm font-semibold text-gray-900">
Contact support <span aria-hidden="true">&rarr;</span>
</a>
</div>
</div>
</main>
);
}

53
app/components/form.tsx Normal file
View file

@ -0,0 +1,53 @@
'use client';
import { useState } from "react";
export enum FieldType {
number = 'number',
text = 'text'
}
export type FormFields = {
type: FieldType,
name: string,
label: string,
required: boolean
}
const Form = <T,>({ fields, onSubmit }) => {
const [formData, setFormData] = useState({});
const handleChange = (event) => {
const { name, value } = event.target;
setFormData( (prevData) => ({
...prevData,
[name]: value
}));
}
const handleSubmit = (event) => {
event.preventDefault();
onSubmit( formData );
}
return (
<form onSubmit={handleSubmit}>
{fields.map( (field) => {
return (
<div key={field.name}>
<label>{field.label}</label>
<input
type={field.type}
name={field.name}
value={formData[field.name] || ''}
onChange={handleChange}
required={field.required}
/>
</div>
)})}
<button type="submit">Submit</button>
</form>
);
}
export default Form;

View file

@ -0,0 +1,26 @@
'use client';
import { motion } from "framer-motion"
import { useState } from "react";
const LinkButton = ({text, href, onPress}: {text: string, href: string, onPress?: () => any}) => {
const [buttonHovered, setButtonHovered] = useState( false );
const [buttonPressed, setButtonPressed] = useState( false );
return (
<div className="mt-10 flex items-center justify-center gap-x-6 lg:justify-start">
<motion.a
href={href}
className="rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{ marginBottom: '40px' }}
animate={{opacity: buttonHovered ? 0.8 : 1}}
onMouseEnter={()=>setButtonHovered(true)}
onMouseLeave={()=>setButtonHovered(false)}
onClick={()=>{setButtonPressed(true); onPress && onPress();}}
>
{text}
</motion.a>
</div>
);
}
export default LinkButton;

45
app/components/logo.tsx Normal file
View file

@ -0,0 +1,45 @@
'use client';
import { Transition } from "@headlessui/react";
import { motion } from "framer-motion";
import { useState } from "react";
import LinkButton from "./link-button";
const Logo = () => {
const [logoHovered, setLogoHovered] = useState( false );
const [aboutButtonHovered, setAboutButtonHovered] = useState( false );
return (
<div style={{ display:"flex", alignItems: 'center', justifyContent: 'center', marginLeft: "40px", marginRight: "40px"}}>
{/* <Transition
appear={false}
show={true}
enter="transition-opacity duration-75"
enterFrom={logoHovered ? "opacity-100" : "opacity-70"}
enterTo={logoHovered ? "opacity-70" : "opacity-100"}
leave="transition-opacity duration-75"
leaveFrom={logoHovered ? "opacity-70" : "opacity-100"}
leaveTo={logoHovered ? "opacity-100" : "opacity-70"}> */}
<motion.a href="/" style={{ marginBottom: '40px', marginLeft: '40px'}} animate={{opacity: logoHovered ? 0.7 : 1}}
onMouseEnter={()=>setLogoHovered(true)}
onMouseLeave={()=>setLogoHovered(false)}>
<img src="/logo-no-background.png" height="auto" width="400px"/>
</motion.a>
{/* </Transition> */}
<div style={{ marginBottom: '40px', marginRight: '50px' }}></div>
{/* <motion.a
href="/about-us"
className="rounded-md bg-white text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{ marginBottom: '40px', marginRight: '40px', padding: '10px' }}
animate={{opacity: aboutButtonHovered ? 0.8 : 1}}
onMouseEnter={()=>setAboutButtonHovered(true)}
onMouseLeave={()=>setAboutButtonHovered(false)}
>
About us
</motion.a> */}
<LinkButton text="About us" href="/about-us"/>
</div>
)
}
export default Logo;

View file

@ -0,0 +1,120 @@
import { ReactComponentElement, ReactNode, useEffect } from "react";
import { AnswerType, Question } from "../lib/question";
import { SessionState } from "../lib/session";
import { CheckCircleIcon, XCircleIcon } from "@heroicons/react/24/outline";
import { Button, Transition } from "@headlessui/react";
import wait from "../lib/delay";
import { motion } from "framer-motion";
const QuestionView = ({ question, setState, state }: { question: Question, setState: any, state: SessionState }) => {
const handleOpenClick = () => {
setState( (prevState: SessionState) => ({
...prevState,
opened: {
...prevState.opened,
[question.id]: !prevState.opened[ question.id ]
}
}))
}
useEffect( () => {
wait( 1000 );
}, [] );
const handleAnswerClick = (right: boolean) => {
setState( (prevState: SessionState) => ({
...prevState,
answered: prevState.answered + 1,
wrong: prevState.wrong + (right ? 0 : 1),
right: prevState.right + (right ? 1 : 0),
answer: {
...prevState.answer,
[question.id]: right ? AnswerType.Right : AnswerType.Wrong
}
}))
question.answered = right ? AnswerType.Right : AnswerType.Wrong;
}
return (
<div className="mx-auto max-w-2xl py-32 sm:py-48 lg:py-56">
<div className="text-center">
{/* {question && question.text} */}
<Transition
appear={true}
show={question ? true : false /* a bit hacky */}
enter="transition-opacity duration-300"
enterFrom="opacity-0"
enterTo="opacity-90"
leave="transition-opacity duration-150"
leaveFrom="opacity-90"
leaveTo="opacity-0">
<h1 className="text-4xl font-bold tracking-tight text-gray-50">
{question.text}
</h1>
</Transition>
{/* <Transition
show={(question && state.opened[ question.id ]) ? true : false}
enter="transition-opacity duration-300"
enterFrom="opacity-0"
enterTo="opacity-90"
leave="transition-opacity duration-150"
leaveFrom="opacity-90"
leaveTo="opacity-0"> */}
{/* <motion.div animate={{visibility: ((question && state.opened[ question.id ]) ? "visible" : "collapse") }}> */}
<motion.div animate={(question && state.opened[ question.id ]) ? {visibility: "visible", opacity: 1} : {visibility: "collapse", opacity: 0}}>
<div><p className="mt-6 text-lg leading-8 text-gray-200">
{question.answer}
</p>
{/* <div className="mt-10 flex items-center justify-center gap-x-6">
<button
onClick={() => { handleAnswerClick( true )}}
className="rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
>
I knew that!
</button>
<button
onClick={() => {handleAnswerClick( false )}}
className="text-sm font-semibold leading-6 text-gray-300"
>
I didn't know that!
</button>
</div> */}
<div className="mt-10 flex items-center justify-center gap-x-6">
<button
onClick={() => { handleAnswerClick( true )}}
className="rounded-md bg-green-600 px-3.5 py-2.5 text-s font-semibold text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
style={{minWidth:'40%', minHeight:'40%', maxWidth:'40%', maxHeight:'40%'}}
>
<CheckCircleIcon></CheckCircleIcon>
I knew that!
</button>
<button
onClick={() => {handleAnswerClick( false )}}
className="rounded-md bg-red-600 px-3.5 py-2.5 text-s font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
style={{minWidth:'40%', minHeight:'40%', maxWidth:'40%', maxHeight:'40%'}}
>
<XCircleIcon></XCircleIcon>
I didn't know!
</button>
</div>
</div>
</motion.div>
<Transition
show={(question && (state.opened[ question.id ])) ? false : true}
enter="transition-opacity duration-300"
enterFrom="opacity-0"
enterTo="opacity-90"
leave="transition-opacity duration-150"
leaveFrom="opacity-90"
leaveTo="opacity-0">
<Button className="leading-6 text-black back rounded-md bg-white text-sm font-semibold text-gray-900" onClick={handleOpenClick} style = {{padding: '5px'}}>
Show answer
</Button>
</Transition>
</div>
</div>
)
}
export default QuestionView;

113
app/components/results.tsx Normal file
View file

@ -0,0 +1,113 @@
import { CheckIcon, XMarkIcon, QuestionMarkCircleIcon, FingerPrintIcon, LockClosedIcon } from '@heroicons/react/24/outline'
import Logo from './logo';
import { SessionState } from '../lib/session';
import LinkButton from './link-button';
/*
const features = [
{
name: 'Correct Questions',
description:
'You got [insert number here] questions right! Good Job!',
icon: CheckIcon,
},
{
name: 'Incorrect Questions',
description:
'You got [insert number here] questions wrong! You can do better!',
icon: XMarkIcon,
},
{
name: 'Total Questions',
description:
'There were [insert number here] questions in total.',
icon: QuestionMarkCircleIcon,
}
]
*/
const Result = ({name, text1, number, text2, Icon}: {name: string, text1: string, number: number, text2: string, Icon: any}) => {
return (
<div className="relative pl-16">
<dt className="text-base font-semibold leading-7 text-gray-100">
<div className="absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-600">
<Icon className="h-6 w-6 text-white" aria-hidden="true"/>
</div>
{name}
</dt>
<dd className="mt-2 text-base leading-7 text-gray-300">{`${text1} ${number} ${text2}`}</dd>
</div>
// {/* <p className="relative pl-16">{`${text1} ${number} ${text2}`}</p> */}
)
}
const ResultScreen = ({state}: {state: SessionState}) => {
return (
<div className="py-24 sm:py-32">
<div
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
aria-hidden="true"
>
<div
className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
</div>
<div style={{paddingBottom: '128px'}}></div>
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl lg:text-center">
<h2 className="text-base font-semibold leading-7 text-indigo-300">You did it!</h2>
<p className="mt-2 text-3xl font-bold tracking-tight text-gray-100 sm:text-4xl">
Here are the results:
</p>
<p className="mt-6 text-lg leading-8 text-gray-600">
On this page you can see what you did at the quiz. We'll give your wrong questions again, another time!
</p>
</div>
<div className="mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-4xl">
<dl className="grid max-w-xl grid-cols-1 gap-x-8 gap-y-10 lg:max-w-none lg:grid-cols-2 lg:gap-y-16">
{/* {features.map((feature) => (
<div key={feature.name} className="relative pl-16">
<dt className="text-base font-semibold leading-7 text-gray-100">
<div className="absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-600">
<feature.icon className="h-6 w-6 text-white" aria-hidden="true" />
</div>
{feature.name}
</dt>
<dd className="mt-2 text-base leading-7 text-gray-300">{feature.description}</dd>
</div>
))} */}
<Result name="Correct Answers" key="correct" text1="Congrats for your" number={state.right} text2="correctly answered questions! Great job!" Icon={CheckIcon}/>
<Result name="Wrong Answers" key="wrong" text1="You had" number={state.wrong} text2="wrong answers... It's never too late to learn!" Icon={XMarkIcon}/>
<Result name="Total Answers" key="total" text1="The" number={state.answered} text2="questions you answered surely helped you learn more." Icon={QuestionMarkCircleIcon}/>
</dl>
<br></br>
{/* <a
href="/sessionconfig"
className="rounded-md bg-indigo-600 px-3.5 py-2.5 text-sm font-semibold text-gray-100 shadow-sm hover:bg-indigo-900 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{ marginTop: '100px' }}
>
Go Back
</a> */}
<LinkButton text="Learn about another topic" href="/sessionconfig"/>
</div>
</div>
<div
className="absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]"
aria-hidden="true"
>
<div
className="relative left-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%+36rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
</div>
</div>
)
}
export default ResultScreen;

View file

@ -0,0 +1,48 @@
'use client';
import { motion } from 'framer-motion';
import { useState } from 'react';
import LinkButton from './link-button';
const TopicCard = ({ title, children, link }: { title: string, children: any, link: string }) => {
const [clicked, setClicked] = useState( false );
const [hovered, setHovered] = useState( false );
return (
<motion.div className="mx-auto mt-16 max-w-2xl rounded-3xl sm:mt-20 lg:mx-0 lg:flex lg:max-w-none relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0" style={{marginTop: '20px', paddingTop: '0px', paddingBottom: '24px'}}
animate={{x: hovered? 10 : 0, opacity: clicked ? 0.5 : 1 }} onMouseEnter={()=>setHovered(true)} onMouseLeave={()=>setHovered(false)}>
<svg
viewBox="0 0 1024 1024"
className="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-1/2 lg:translate-y-0"
aria-hidden="true"
>
<circle cx={512} cy={512} r={512} fill="url(#759c1415-0410-454c-8f7c-9a820de03641)" fillOpacity="0.7" />
<defs>
<radialGradient id="759c1415-0410-454c-8f7c-9a820de03641">
<stop stopColor="#7775D6" />
<stop offset={1} stopColor="#E935C1" />
</radialGradient>
</defs>
</svg>
<div className="p-8 sm:p-10 lg:flex-auto ">
<h3 className="text-2xl font-bold tracking-tight text-gray-200">{title}</h3>
<p className="mt-6 text-base leading-7 text-gray-200">
{children}
</p>
</div>
<div
className="-mt-2 p-2 lg:mt-0 lg:max-w-md lg:flex-shrink-0 lg:flex lg:flex-col lg:justify-center"
style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}
>
{/* <a
href={link}
className="rounded-md text-sm font-semibold border text-gray-200 shadow-sm hover:text-gray-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
style={{ paddingLeft: '50px', paddingRight: '50px', paddingTop: '20px', paddingBottom: '20px'}}
>
Begin
</a> */}
<LinkButton text="Begin" href={link} onPress={()=>setClicked(true)}/>
</div>
</motion.div>
)
}
export default TopicCard;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 258 KiB

View file

@ -5,8 +5,8 @@ import "./globals.css";
const inter = Inter({ subsets: ["latin"] }); const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Create Next App", title: "FlashLearn",
description: "Generated by create next app", description: "A react based, flashcard app.",
}; };
export default function RootLayout({ export default function RootLayout({

View file

@ -0,0 +1,124 @@
'use client';
import { useEffect, useState } from 'react'
import { Dialog, DialogPanel } from '@headlessui/react'
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
import Logo from '../../components/logo';
import { CheckIcon } from '@heroicons/react/20/solid';
import { SessionState } from '@/app/lib/session';
import { AnswerType, Question, getQuestions } from '@/app/lib/question';
import QuestionView from '@/app/components/question_component';
import ResultScreen from '@/app/components/results';
const shuffle = (array: any[]) => {
let i = array.length - 1;
while ( i >= 0 ) {
const random_i = Math.floor( Math.random() * i );
[array[ i ], array[ random_i ]] = [array[ random_i ], array[ i ]];
i--;
}
}
const Page = ({ params }: { params: { category: string }}) => {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
const [state, setState]: [SessionState, any] = useState<SessionState>( {
answered: 0,
wrong: 0,
right: 0,
category: '',
opened: [],
answer: []
} );
// const category = params.category;
// const [all_questions, set_all_questions] = useState<Question[]>([]);
const [questions, setQuestions] = useState<Question[]>([]);
useEffect( () => {
// console.log( params.category );
const fetch_all_questions = async () => {
let result = await getQuestions();
console.log( `all_questions: ${ JSON.stringify( result ) }` );
// set_all_questions( result );
result = result.filter( q => q.category === params.category)
.map(it=>({...it, answered: AnswerType.Unset}));
//result = result.filter
shuffle( result );
setQuestions( result );
console.log( `q12 uestions: ${ JSON.stringify( questions ) }`, result );
}
fetch_all_questions();
var ans: AnswerType[];
questions?.forEach(q => {
ans[ q.id ] = AnswerType.Unset;
});
/*
setState( (prevState: SessionState) => ({
...prevState,
answer: ans
}));
*/
}, [ params.category ]);
console.log( "questions16", questions );
console.log( "state15", state );
// alternate version (show all of them at the same time):
// {/* {questions.map( (q) => (q.answered == AnswerType.Unset) ? <QuestionView key = {q.id} question={q} state={state} setState={setState}/> : <></>)} */}
const index = state.answered;
console.log( "index18", index )
return (
<div>
<div className="relative isolate px-6 pt-14 lg:px-8">
<div style={{paddingTop: '72px'}}></div>
<Logo/>
<div
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
aria-hidden="true"
>
<div
className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
<div
className="relative left-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%+36rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
</div>
{(()=>{
if ( !questions[ 0 ] )
return <></>;
return (index < 10 && questions[ index ]) ? <QuestionView question={questions[ index ]} state = {state} setState={setState}/> : <ResultScreen state={state}/>;
})()}
{/* {questions[ 0 ] ? ((index < 10 && questions[ index ]) ? <QuestionView question={questions[ index ]} state = {state} setState={setState}/> : <ResultScreen state={state}/>) : null} */}
<div
className="absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]"
aria-hidden="true"
>
</div>
</div>
</div>
)
}
export default Page;

87
app/learn/page.tsx Normal file
View file

@ -0,0 +1,87 @@
import { CheckIcon } from '@heroicons/react/20/solid'
import TopicCard from '../components/topic_card'
import Logo from '../components/logo';
import { Transition } from '@headlessui/react';
const includedFeatures = [
'Private forum access',
'Member resources',
'Entry to annual conference',
'Official member t-shirt',
]
export default function Example() {
//List of topics
const cards = [
["Learn cybersecurity", "Learning cybersecurity is like becoming a guardian of the digital realm.\nIt's about mastering the art of protecting information, systems, and networks from cyber threats.\nFrom understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.", "/learn/cybersec" ],
["Learn geography", "Geography is the study of our world's intricate tapestry — from the towering peaks of the Himalayas to the vast expanse of the Sahara Desert. It's about understanding the relationships between people, places, and the environment.", "/learn/geography"],
["Learn CPP", "As a powerful, versatile language, CPP teaches you the fundamentals of object-oriented programming while offering fine-grained control over system resources. You'll explore concepts like classes, inheritance, and polymorphism, alongside memory management and pointers.", "/learn/cpp"]
];
return (
<div className="py-24 sm:py-32" style = {{ alignItems: 'center', justifyContent: 'center' }}>
{/*Background*/}
<div
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
aria-hidden="true"
>
<div
className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
<div
className="relative left-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%+36rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
</div>
{/*The logo*/}
<Logo/>
<div style={{paddingTop: '128px'}}></div>
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<Transition
appear={true}
show={true}
enter="transition-opacity duration-300"
enterFrom="opacity-0"
enterTo="opacity-80">
<div>
{ cards.map((elem) => {
return (
<TopicCard title={elem[0]} link={elem[2]}>{elem[1]}</TopicCard>
)})}
</div>
</Transition>
{/*
<TopicCard title = "Learn cybersecurity">
Learning cybersecurity is like becoming a guardian of the digital realm.
It's about mastering the art of protecting information, systems, and networks from cyber threats.
From understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.
</TopicCard>
<TopicCard title = "Learn geography">
Learning cybersecurity is like becoming a guardian of the digital realm.
It's about mastering the art of protecting information, systems, and networks from cyber threats.
From understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.
</TopicCard>
<TopicCard title = "Learn C++">
Learning cybersecurity is like becoming a guardian of the digital realm.
It's about mastering the art of protecting information, systems, and networks from cyber threats.
From understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.
</TopicCard>
*/}
</div>
{/*Background*/}
<div
className="absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]"
aria-hidden="true"
>
</div>
</div>
)
}

33
app/lib/api.ts Normal file
View file

@ -0,0 +1,33 @@
// the base URL of the api; all requests start with it
const base_url: string = "https://api.phite.ro/";
/*
export const makeGetRequest = async<T> (path: string): Promise<T> => {
return await (await fetch( base_url + path )).json();
}
*/
// generic function that makes a web request
const makeRequest = async (path: string, method: string, body?: string): Promise<Response> => {
console.log( `making ${method} request: ${base_url + path}, ${body}` );
return fetch( base_url + path, { method: method, body: body ? body : null } );
}
// the following functions are wrappers around `makeRequest`,
// for every type of request that's needed.
export const makeGetRequest = async<T> (path: string): Promise<T> => {
return (await makeRequest( path, "GET" )).json();
}
export const makePostRequest = async<T> (path: string, body: T): Promise<T> => {
return (await makeRequest( path, "POST", JSON.stringify( body ) )).json();
}
export const makePutRequest = async<T> (path: string, body: T): Promise<T> => {
return (await makeRequest( path, "PUT", JSON.stringify( body ) )).json();
}
export const makeDeleteRequest = async<T> (path: string): Promise<T> => {
return (await makeRequest( path, "DELETE" )).json();
}

5
app/lib/delay.ts Normal file
View file

@ -0,0 +1,5 @@
const wait = (time: number): Promise<void> => {
return new Promise( res => setTimeout( res, time ) );
}
export default wait;

44
app/lib/question.ts Normal file
View file

@ -0,0 +1,44 @@
import { makeDeleteRequest, makeGetRequest, makePostRequest } from "./api";
export const enum QuizQuestion {
UL,
UR,
DL,
DR
};
export const enum AnswerType {
Unset,
Right,
Wrong
};
export type Question = {
id: number;
category: string | null;
type?: string; // TODO: make a TS type for every question type
text: string;
answer: string | boolean | QuizQuestion;
answered?: AnswerType;
}
export const getQuestion = async (id: number): Promise<Question> => {
return makeGetRequest( `questions/${id}/` );
}
export const getQuestions = async (): Promise<Question[]> => {
return makeGetRequest( `questions/` );
}
export const addQuestion = async (question: Question): Promise<Question> => {
console.log( `adding question ${JSON.stringify( question)}` );
return makePostRequest( `questions`, question );
}
export const editQuestion = async (question: Question): Promise<Question> => {
return makePostRequest( `questions/${question.id}`, question );
}
export const deleteQuestion = async (id: number): Promise<Question> => {
return makeDeleteRequest( `questions/${id}` );
}

27
app/lib/session.ts Normal file
View file

@ -0,0 +1,27 @@
import { makeGetRequest, makePostRequest } from "./api";
import { AnswerType } from "./question";
export type Session = {
id: number;
right: number;
wrong: number;
total: number;
// user: string;
}
export type SessionState = {
answered: number;
wrong: number;
right: number;
category: string;
opened: boolean[];
answer: AnswerType[];
}
export const getSession = async (id: number): Promise<Session> => {
return makeGetRequest( `sessions/${id}/` );
}
export const postSession = async (session: Session): Promise<Session> => {
return makePostRequest( `sessions`, session );
}

View file

@ -1,113 +1,102 @@
import Image from "next/image"; 'use client';
import { Fragment, useState } from 'react'
export default function Home() { import { Menu, MenuButton, MenuItem, MenuItems, Transition } from '@headlessui/react'
return ( import { ChevronDownIcon } from '@heroicons/react/20/solid'
<main className="flex min-h-screen flex-col items-center justify-between p-24"> import Logo from './components/logo';
<div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm lg:flex"> import { motion } from 'framer-motion';
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl dark:border-neutral-800 dark:bg-zinc-800/30 dark:from-inherit lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30"> import LinkButton from './components/link-button';
Get started by editing&nbsp; function classNames(...classes) {
<code className="font-mono font-bold">app/page.tsx</code> return classes.filter(Boolean).join(' ')
</p> }
<div className="fixed bottom-0 left-0 flex h-48 w-full items-end justify-center bg-gradient-to-t from-white via-white dark:from-black dark:via-black lg:static lg:size-auto lg:bg-none"> export default function Example() {
<a const [buttonPressed, setButtonPressed] = useState( false );
className="pointer-events-none flex place-items-center gap-2 p-8 lg:pointer-events-auto lg:p-0" return (
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app" <div>
target="_blank" {/*Background visual elements*/}
rel="noopener noreferrer" <div
> className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
By{" "} aria-hidden="true"
<Image >
src="/vercel.svg" <div
alt="Vercel Logo" className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
className="dark:invert" style={{
width={100} clipPath:
height={24} 'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
priority }}
/> />
</a> <div
</div> className="relative left-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%+36rem)] sm:w-[72.1875rem]"
</div> style={{
clipPath:
<div className="relative z-[-1] flex place-items-center before:absolute before:h-[300px] before:w-full before:-translate-x-1/2 before:rounded-full before:bg-gradient-radial before:from-white before:to-transparent before:blur-2xl before:content-[''] after:absolute after:-z-20 after:h-[180px] after:w-full after:translate-x-1/3 after:bg-gradient-conic after:from-sky-200 after:via-blue-200 after:blur-2xl after:content-[''] before:dark:bg-gradient-to-br before:dark:from-transparent before:dark:to-blue-700 before:dark:opacity-10 after:dark:from-sky-900 after:dark:via-[#0141ff] after:dark:opacity-40 sm:before:w-[480px] sm:after:w-[240px] before:lg:h-[360px]"> 'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
<Image }}
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert" />
src="/next.svg" </div>
alt="Next.js Logo" <div style={{paddingTop: '128px'}}></div>
width={180} <Logo/>
height={37} <Transition
priority appear={true}
/> show={!buttonPressed}
</div> enter="transition-opacity duration-500"
enterFrom="opacity-0"
<div className="mb-32 grid text-center lg:mb-0 lg:w-full lg:max-w-5xl lg:grid-cols-4 lg:text-left"> enterTo="opacity-80"
<a leave="transition-opacity duration-150"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app" leaveFrom="opacity-80"
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30" leaveTo="opacity-0">
target="_blank" <div className="mx-auto max-w-7xl py-24 sm:px-6 sm:py-32 lg:px-8">
rel="noopener noreferrer" <div className="relative isolate overflow-hidden bg-gray-900 px-6 pt-16 shadow-2xl sm:rounded-3xl sm:px-16 md:pt-24 lg:flex lg:gap-x-20 lg:px-24 lg:pt-0">
> <svg
<h2 className="mb-3 text-2xl font-semibold"> viewBox="0 0 1024 1024"
Docs{" "} className="absolute left-1/2 top-1/2 -z-10 h-[64rem] w-[64rem] -translate-y-1/2 [mask-image:radial-gradient(closest-side,white,transparent)] sm:left-full sm:-ml-80 lg:left-1/2 lg:ml-0 lg:-translate-x-1/2 lg:translate-y-0"
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none"> aria-hidden="true"
-&gt; >
</span> <circle cx={512} cy={512} r={512} fill="url(#759c1415-0410-454c-8f7c-9a820de03641)" fillOpacity="0.7" />
</h2> <defs>
<p className="m-0 max-w-[30ch] text-sm opacity-50"> <radialGradient id="759c1415-0410-454c-8f7c-9a820de03641">
Find in-depth information about Next.js features and API. <stop stopColor="#7775D6" />
</p> <stop offset={1} stopColor="#E935C1" />
</a> </radialGradient>
</defs>
<a </svg>
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app" <div className="mx-auto max-w-md text-center lg:mx-0 lg:flex-auto lg:py-32 lg:text-left">
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30" <h2 className="text-3xl font-bold tracking-tight text-white sm:text-4xl">
target="_blank" Start using flash cards
rel="noopener noreferrer" <br />
> Begin with our app today.
<h2 className="mb-3 text-2xl font-semibold"> </h2>
Learn{" "} <p className="mt-6 text-lg leading-8 text-gray-300">
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none"> Get questions from a multitude of different subjects that include cybersecurity, geography and C++
-&gt; </p>
</span> <div className="mt-10 flex items-center justify-center gap-x-6 lg:justify-start">
</h2> {/* <motion.a
<p className="m-0 max-w-[30ch] text-sm opacity-50"> href="sessionconfig"
Learn about Next.js in an interactive course with&nbsp;quizzes! className="rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold text-gray-900 shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white"
</p> style={{ marginBottom: '40px' }}
</a> animate={{opacity: buttonHovered ? 0.8 : 1}}
onMouseEnter={()=>setButtonHovered(true)}
<a onMouseLeave={()=>setButtonHovered(false)}
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app" onClick={()=>setButtonPressed(true)}
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30" >
target="_blank" Get started
rel="noopener noreferrer" </motion.a> */}
> <LinkButton text="Get started" href="/sessionconfig" onPress={()=>setButtonPressed(true)}/>
<h2 className="mb-3 text-2xl font-semibold"> </div>
Templates{" "} </div>
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none"> </div>
-&gt; </div>
</span> </Transition>
</h2> <div
<p className="m-0 max-w-[30ch] text-sm opacity-50"> className="absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]"
Explore starter templates for Next.js. aria-hidden="true"
</p> >
</a> <div
className="relative left-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%+36rem)] sm:w-[72.1875rem]"
<a style={{
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app" clipPath:
className="group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30" 'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
target="_blank" }}
rel="noopener noreferrer" />
> </div>
<h2 className="mb-3 text-2xl font-semibold"> </div>
Deploy{" "} )
<span className="inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none">
-&gt;
</span>
</h2>
<p className="m-0 max-w-[30ch] text-balance text-sm opacity-50">
Instantly deploy your Next.js site to a shareable URL with Vercel.
</p>
</a>
</div>
</main>
);
} }

View file

@ -0,0 +1,87 @@
import { CheckIcon } from '@heroicons/react/20/solid'
import TopicCard from '../components/topic_card'
import Logo from '../components/logo';
import { Transition } from '@headlessui/react';
const includedFeatures = [
'Private forum access',
'Member resources',
'Entry to annual conference',
'Official member t-shirt',
]
export default function Example() {
//List of topics
const cards = [
["Learn cybersecurity", "Learning cybersecurity is like becoming a guardian of the digital realm.\nIt's about mastering the art of protecting information, systems, and networks from cyber threats.\nFrom understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.", "/learn/cybersec" ],
["Learn geography", "Geography is the study of our world's intricate tapestry — from the towering peaks of the Himalayas to the vast expanse of the Sahara Desert. It's about understanding the relationships between people, places and the environment.", "/learn/geography"],
["Learn CPP", "As a powerful, versatile language, C++ teaches you the fundamentals of object-oriented programming while offering fine-grained control over system resources. You'll explore concepts like classes, inheritance, and polymorphism, alongside memory management and pointers.", "/learn/cpp"]
];
return (
<div className="py-24 sm:py-32" style = {{ alignItems: 'center', justifyContent: 'center' }}>
{/*Background*/}
<div
className="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
aria-hidden="true"
>
<div
className="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
<div
className="relative left-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%+36rem)] sm:w-[72.1875rem]"
style={{
clipPath:
'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',
}}
/>
</div>
{/*The logo*/}
<Logo/>
<div style={{paddingTop: '128px'}}></div>
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<Transition
appear={true}
show={true}
enter="transition-opacity duration-300"
enterFrom="opacity-0"
enterTo="opacity-80">
<div>
{ cards.map((elem) => {
return (
<TopicCard title={elem[0]} link={elem[2]}>{elem[1]}</TopicCard>
)})}
</div>
</Transition>
{/*
<TopicCard title = "Learn cybersecurity">
Learning cybersecurity is like becoming a guardian of the digital realm.
It's about mastering the art of protecting information, systems, and networks from cyber threats.
From understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.
</TopicCard>
<TopicCard title = "Learn geography">
Learning cybersecurity is like becoming a guardian of the digital realm.
It's about mastering the art of protecting information, systems, and networks from cyber threats.
From understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.
</TopicCard>
<TopicCard title = "Learn C++">
Learning cybersecurity is like becoming a guardian of the digital realm.
It's about mastering the art of protecting information, systems, and networks from cyber threats.
From understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.
</TopicCard>
*/}
</div>
{/*Background*/}
<div
className="absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]"
aria-hidden="true"
>
</div>
</div>
)
}

40
package-lock.json generated
View file

@ -10,9 +10,11 @@
"dependencies": { "dependencies": {
"@headlessui/react": "^2.0.4", "@headlessui/react": "^2.0.4",
"@heroicons/react": "^2.1.3", "@heroicons/react": "^2.1.3",
"framer-motion": "^11.2.10",
"next": "14.2.3", "next": "14.2.3",
"react": "^18", "react": "^18",
"react-dom": "^18" "react-dom": "^18",
"react-use-wizard": "^2.3.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20", "@types/node": "^20",
@ -2244,6 +2246,30 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/framer-motion": {
"version": "11.2.10",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.2.10.tgz",
"integrity": "sha512-/gr3PLZUVFCc86a9MqCUboVrALscrdluzTb3yew+2/qKBU8CX6nzs918/SRBRCqaPbx0TZP10CB6yFgK2C5cYQ==",
"dependencies": {
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -3911,6 +3937,18 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true "dev": true
}, },
"node_modules/react-use-wizard": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/react-use-wizard/-/react-use-wizard-2.3.0.tgz",
"integrity": "sha512-z06pQNZ18FvoK+ZDW50hOf0uOySo0Hhd7H4y0MLyk/tBCwpUKGBeULosORBVhipUaWihNLpLJxwH5f+85Qt5XA==",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
},
"node_modules/read-cache": { "node_modules/read-cache": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",

View file

@ -11,9 +11,11 @@
"dependencies": { "dependencies": {
"@headlessui/react": "^2.0.4", "@headlessui/react": "^2.0.4",
"@heroicons/react": "^2.1.3", "@heroicons/react": "^2.1.3",
"framer-motion": "^11.2.10",
"next": "14.2.3", "next": "14.2.3",
"react": "^18", "react": "^18",
"react-dom": "^18" "react-dom": "^18",
"react-use-wizard": "^2.3.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20", "@types/node": "^20",

BIN
public/alex.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
public/andrei.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

BIN
public/arch.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
public/blahaj.avif Normal file

Binary file not shown.

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

BIN
public/ioan.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -12,6 +12,7 @@
"isolatedModules": true, "isolatedModules": true,
"jsx": "preserve", "jsx": "preserve",
"incremental": true, "incremental": true,
"noImplicitAny": false,
"plugins": [ "plugins": [
{ {
"name": "next" "name": "next"
@ -21,6 +22,6 @@
"@/*": ["./*"] "@/*": ["./*"]
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "app/components/Dropdown.js"],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }