Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Courses page #641

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions new-dti-website/components/courses/DDProjects.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React, { useState } from 'react';

interface DDProjectsProps {
title: string;
description: string;
imageSrc: string;
}

/**
* `DDProjects` Component - Displays information about past student Projects within Trends :)
*
* @remarks
* This component is used to present information about student projects, including the title,
* description, and an image representing the project that they did in Trends class. There is an interactive expand/collapse
* functionality, allowing the user to toggle additional details with a smooth transition effect.
* The card's background color changes based on its state (open/closed). The component is also responsive to screen size.
*
* The component is designed to receive data via props and a json object.
*
* @param props - Contains:
* - `title`: The title of the project, displayed prominently at the top of the card.
* - `description`: A brief description of the project, revealed when the card is expanded.
* - `imageSrc`: The URL for the image that represents the project, displayed in the expanded view.
*/
export default function DDProjects({ title, description, imageSrc }: DDProjectsProps) {
const [isOpen, setIsOpen] = useState(false);

const toggleCard = () => {
setIsOpen(!isOpen);
};

return (
<div
className={`transition-all duration-300 ease-in-out ${
isOpen ? 'bg-[#D63D3D]' : 'bg-white'
} w-full max-w-8xl rounded-xl drop-shadow-sm px-10 py-8 border-1 border-[#E4E4E4]`}
>
<div className="flex justify-between items-center">
<h3 className={`md:text-3xl text-xl font-bold ${isOpen ? 'text-white' : 'text-black'}`}>
{title}
</h3>
<button
className={`md:text-4xl text-2xl font-thin ${isOpen ? 'text-white' : 'text-gray-700'}`}
onClick={toggleCard}
>
{isOpen ? '−' : '+'}
</button>
</div>

{/* Smooth transition for the Additional Content onClick */}
<div
className={`overflow-hidden transition-all duration-700 ease-in-out ${
isOpen ? 'max-h-96 opacity-100' : 'max-h-0 opacity-0'
}`}
>
<div className="mt-4">
<p className="text-white">{description}</p>
<img src={imageSrc} alt={title} className="mt-4 w-full h-48 object-cover rounded-lg" />
</div>
</div>
</div>
);
}
43 changes: 43 additions & 0 deletions new-dti-website/components/courses/Experiences.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import Image from 'next/image';

interface IconProps {
icon: string;
title: string;
description: string;
}

/**
* `Experiences` Component - Displays key experiences for students in Trends :)
*
* @remarks
* This component is used to highlight three core experiences students will get from Trends,
* including best practices, deploying web applications, and completing a final project. Each experience consists
* of an icon, a title, and a brief description. The component adapts its layout based on screen size, with responsive
* text sizes and image scaling.
*
* @param props - Contains:
* - `icon`: The URL path to the icon image associated with the experience.
* - `title`: The title of the key experience.
* - `description`: A short description about the past student's projects.
*/
export default function Experiences({ icon, title, description }: IconProps) {
return (
<>
<div className="flex flex-col max-w-[450px]">
<div className="flex flex-col items-start md:flex-row md:items-center">
<Image
src={icon}
width={150}
height={150}
alt={icon}
unoptimized
className="w-24 md:w-[30%]"
/>
<div className="text-4xl font-extrabold">{title}</div>
</div>
<div className="mt-8 text-lg md:text-md lg:text-2xl">{description}</div>
</div>
</>
);
}
34 changes: 34 additions & 0 deletions new-dti-website/components/courses/TestimonialCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';

export interface TestimonialCardProps {
description: string;
name: string;
semesterTaken: string;
}

/**
* `TestimonialCard` Component - Displays a single testimonial from a student who has done Trends.
*
* @remarks
* This component is used to present testimonials from students about their experiences taking the course. It showcases
* a brief description of the testimonial, the name of the student (or anonymous), and the semester in which they took the class.
*
* @param props - Contains:
* - `description`: The student's written testimonial about the course.
* - `name`: The name of the student who gave the testimonial, or "Anonymous" if the student prefers not to disclose their name.
* - `semesterTaken`: The semester when the student took the course.
*/
export default function TestimonialCard({
description,
name,
semesterTaken
}: TestimonialCardProps) {
return (
<div className="bg-white max-w-md w-[800px] p-10 rounded-xl drop-shadow-sm flex-shrink-0">
<div className="text-3xl text-gray-800 mb-4 tracking-wider font-black">❛❛</div>
<p className="text-lg text-gray-700 mb-6">{description}</p>
<div className="text-gray-900 font-bold pt-8">{name}</div>
<div className="text-gray-500">{semesterTaken}</div>
</div>
);
}
65 changes: 65 additions & 0 deletions new-dti-website/components/courses/TestimonialSlider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useRef, useState, useEffect } from 'react';
import TestimonialCard, { TestimonialCardProps } from './TestimonialCard';

interface TestimonialSliderProps {
testimonials: TestimonialCardProps[];
}

export default function TestimonialSlider({ testimonials }: TestimonialSliderProps) {
const sliderRef = useRef<HTMLDivElement | null>(null);
const [isScrolling, setIsScrolling] = useState(false);
const [scrollAtEnd, setScrollAtEnd] = useState(false);

useEffect(() => {
const slider = sliderRef.current;

// Return early if there are no testimonials or if we've reached the end
if (!slider || testimonials.length === 0 || scrollAtEnd || isScrolling) {
return undefined; // Return `undefined` explicitly to satisfy consistent-return rule
}

const scrollInterval = setInterval(() => {
const maxScrollLeft = slider.scrollWidth - slider.clientWidth;

if (slider.scrollLeft < maxScrollLeft) {
slider.scrollLeft += 2; // Adjust the scroll speed as needed
} else {
setScrollAtEnd(true); // Stop scrolling when the end is reached
// slider.scrollLeft = 0 if we want to start from the begnning :)
}
}, 25); // Adjust the interval as needed for smoother/faster scrolling

// Return the cleanup function
return () => {
clearInterval(scrollInterval);
};
}, [testimonials, isScrolling, scrollAtEnd]);

const handleMouseEnter = () => {
setIsScrolling(true);
};

const handleMouseLeave = () => {
setIsScrolling(false);
};

return (
<div
className="overflow-x-auto pt-14"
ref={sliderRef}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div className="flex gap-x-12 px-10 sm:px-32 flex-nowrap">
{testimonials.map((testimonial, index) => (
<TestimonialCard
key={index}
description={testimonial.description}
name={testimonial.name}
semesterTaken={testimonial.semesterTaken}
/>
))}
</div>
</div>
);
}
Loading
Loading