Added a TopicCard component (#6)

This commit is contained in:
Alex Stan 2024-06-01 15:47:53 +03:00
parent fda1fae418
commit 4a98209021
6 changed files with 204 additions and 127 deletions

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

@ -0,0 +1,47 @@
'use client';
import { useState } from "react";
const Form = <T,>({ initialData, onSubmit }) => {
const [formData, setFormData] = useState( initialData );
const handleSubmit = (event) => {
event.preventDefault();
//q = formData;
//addQuestion( q );
//console.log( `Adding question ${JSON.stringify(q)}` );
onSubmit( formData );
}
const handleChange = (event) => {
const { name, value } = event.target;
setFormData( (prevData) => ({
...prevData,
[name]: value
}));
}
return (
<form onSubmit={handleSubmit} className="flex">
<div>
{Object.entries( initialData ).map( (key, val) => {
return(
<input
type = { typeof( val ) == typeof( 0 ) ? "number" : "text" /* pretty hacky, we should change this */ }
id = {key[0]}
name = {key[0]}
value = {formData[key[0]]}
onChange = {handleChange}
required
/>)})}
</div>
<button type="submit">Submit</button>
</form>
);
}
export default Form;

View file

@ -0,0 +1,44 @@
const TopicCard = ({ title, children, link }) => {
return(
<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">
<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:w-full lg:max-w-md lg:flex-shrink-0">
<div className="rounded-2xl bg-gray-50 py-10 text-center ring-1 ring-inset ring-gray-900/5 lg:flex lg:flex-col lg:justify-center lg:py-16">
<div className="mx-auto max-w-xs px-8">
<p className="mt-6 flex items-baseline justify-center gap-x-2">
<span className="text-5xl font-bold tracking-tight text-gray-900">Start</span>
<span className="text-sm font-semibold leading-6 tracking-wide text-gray-900">now!</span>
</p>
<a
href={link}
className="mt-10 block w-full rounded-md bg-indigo-600 px-3 py-2 text-center 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"
>
Begin
</a>
</div>
</div>
</div>
</div>
)
}
export default TopicCard;

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 = "http://localhost:4000/";
/*
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();
}

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

@ -0,0 +1,33 @@
import { makeDeleteRequest, makeGetRequest, makePostRequest } from "./api";
export const enum QuizQuestion {
UL,
UR,
DL,
DR
};
export type Question = {
id: number;
category: string | null;
type: string | null; // TODO: make a TS type for every question type
text: string;
answer: string | boolean | QuizQuestion;
}
export const getQuestion = async (id: number): Promise<Question> => {
return makeGetRequest( `questions/${id}/` );
}
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}` );
}

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

@ -0,0 +1,17 @@
import { makeGetRequest, makePostRequest } from "./api";
export type Session = {
id: number;
right: number;
wrong: number;
total: number;
// user: string;
}
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,4 +1,5 @@
import { CheckIcon } from '@heroicons/react/20/solid' import { CheckIcon } from '@heroicons/react/20/solid'
import TopicCard from '../components/topic_card'
const includedFeatures = [ const includedFeatures = [
'Private forum access', 'Private forum access',
@ -8,136 +9,38 @@ const includedFeatures = [
] ]
export default function Example() { export default function Example() {
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", "It's cool ig", "/learn/geography"],
["Learn C++", "Don't.", "/learn/cpp"],
["Learn C", "Do.", "/learn/c"]
];
return ( return (
<div className="bg-black py-24 sm:py-32"> <div className="bg-black py-24 sm:py-32">
<div style={{ display:"flex", alignItems: 'center', justifyContent: 'center', paddingTop:'40px'}}><img className="flex" src="/logo-no-background.png" height="auto" width="40%" style={{ alignSelf: 'center'}}></img></div> <div style={{ display:"flex", alignItems: 'center', justifyContent: 'center', paddingTop:'40px'}}><img className="flex" src="/logo-no-background.png" height="auto" width="40%" style={{ alignSelf: 'center'}}></img></div>
<div className="mx-auto max-w-7xl px-6 lg:px-8"> <div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto mt-16 max-w-2xl rounded-3xl ring-1 ring-gray-200 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"> { cards.map((elem) => {
<svg return (<TopicCard title={elem[0]} link={elem[2]}>{elem[1]}</TopicCard>)
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" <TopicCard title = "Learn cybersecurity">
> Learning cybersecurity is like becoming a guardian of the digital realm.
<circle cx={512} cy={512} r={512} fill="url(#759c1415-0410-454c-8f7c-9a820de03641)" fillOpacity="0.7" /> It's about mastering the art of protecting information, systems, and networks from cyber threats.
<defs> From understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.
<radialGradient id="759c1415-0410-454c-8f7c-9a820de03641"> </TopicCard>
<stop stopColor="#7775D6" /> <TopicCard title = "Learn geography">
<stop offset={1} stopColor="#E935C1" /> Learning cybersecurity is like becoming a guardian of the digital realm.
</radialGradient> It's about mastering the art of protecting information, systems, and networks from cyber threats.
</defs> From understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.
</svg> </TopicCard>
<div className="p-8 sm:p-10 lg:flex-auto "> <TopicCard title = "Learn C++">
<h3 className="text-2xl font-bold tracking-tight text-gray-200">Learn cybersecurity</h3> Learning cybersecurity is like becoming a guardian of the digital realm.
<p className="mt-6 text-base leading-7 text-gray-200"> It's about mastering the art of protecting information, systems, and networks from cyber threats.
Learning cybersecurity is like becoming the guardian of the digital realm. From understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks.
It's about mastering the art of protecting information, systems, and networks from cyber threats. </TopicCard>
From understanding encryption algorithms to detecting malware, every lesson equips you with tools to fortify against cyber-attacks. */}
</p>
</div>
<div className="-mt-2 p-2 lg:mt-0 lg:w-full lg:max-w-md lg:flex-shrink-0">
<div className="rounded-2xl bg-gray-50 py-10 text-center ring-1 ring-inset ring-gray-900/5 lg:flex lg:flex-col lg:justify-center lg:py-16">
<div className="mx-auto max-w-xs px-8">
<p className="mt-6 flex items-baseline justify-center gap-x-2">
<span className="text-5xl font-bold tracking-tight text-gray-900">Start</span>
<span className="text-sm font-semibold leading-6 tracking-wide text-gray-900">now!</span>
</p>
<a
href="#"
className="mt-10 block w-full rounded-md bg-indigo-600 px-3 py-2 text-center 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"
>
Begin
</a>
<p className="mt-6 text-xs leading-5 text-gray-600">
Take a short quiz to begin learning faster than ever
</p>
</div>
</div>
</div>
</div>
<div className="mx-auto mt-16 max-w-2xl rounded-3xl ring-1 ring-gray-200 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">
<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>earn cybersecurity
<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">Learn cybersecurity</h3>
<p className="mt-6 text-base leading-7 text-gray-200">
Learning cybersecurity is like becoming the 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.
</p>
</div>
<div className="-mt-2 p-2 lg:mt-0 lg:w-full lg:max-w-md lg:flex-shrink-0">
<div className="rounded-2xl bg-gray-50 py-10 text-center ring-1 ring-inset ring-gray-900/5 lg:flex lg:flex-col lg:justify-center lg:py-16">
<div className="mx-auto max-w-xs px-8">
<p className="mt-6 flex items-baseline justify-center gap-x-2">
<span className="text-5xl font-bold tracking-tight text-gray-900">Start</span>
<span className="text-sm font-semibold leading-6 tracking-wide text-gray-900">now!</span>
</p>earn cybersecurity
<a
href="#"
className="mt-10 block w-full rounded-md bg-indigo-600 px-3 py-2 text-center 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"
>
Begin
</a>
<p className="mt-6 text-xs leading-5 text-gray-600">
Take a short quiz to begin learning faster than ever
</p>
</div>
</div>
</div>
</div>
<div className="mx-auto mt-16 max-w-2xl rounded-3xl ring-1 ring-gray-200 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">
<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">Learn cybersecurity</h3>
<p className="mt-6 text-base leading-7 text-gray-200">
Learning cybersecurity is like becoming the 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.
</p>
</div>
<div className="-mt-2 p-2 lg:mt-0 lg:w-full lg:max-w-md lg:flex-shrink-0">
<div className="rounded-2xl bg-gray-50 py-10 text-center ring-1 ring-inset ring-gray-900/5 lg:flex lg:flex-col lg:justify-center lg:py-16">
<div className="mx-auto max-w-xs px-8">
<p className="mt-6 flex items-baseline justify-center gap-x-2">
<span className="text-5xl font-bold tracking-tight text-gray-900">Start</span>
<span className="text-sm font-semibold leading-6 tracking-wide text-gray-900">now!</span>
</p>
<a
href="#"
className="mt-10 block w-full rounded-md bg-indigo-600 px-3 py-2 text-center 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"
>
Begin
</a>
<p className="mt-6 text-xs leading-5 text-gray-600">
Take a short quiz to begin learning faster than ever
</p>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
) )