Skip to content

Commit

Permalink
feat(ui): Landing page (#267)
Browse files Browse the repository at this point in the history
* chore: Handle white-spaces on languages templates names

* feat(ui): Hero section

* feat(ui): Add features section to home page

* chore: Remove repositories links from footer

Since there are many repositories, organization profile is enough

* feat(ui): Add open-source section
  • Loading branch information
PedroChaparro authored Jan 21, 2024
1 parent 7f2a8f3 commit 254b541
Show file tree
Hide file tree
Showing 20 changed files with 240 additions and 26 deletions.
9 changes: 0 additions & 9 deletions e2e/Footer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,4 @@ test("Footer should contain the correct links", async ({ page }) => {
await expect(
page.getByRole("link", { name: "Organization profile", exact: true })
).toBeVisible();
await expect(
page.getByRole("link", { name: "Frontend repository", exact: true })
).toBeVisible();
await expect(
page.getByRole("link", { name: "Main API repository", exact: true })
).toBeVisible();
await expect(
page.getByRole("link", { name: "Tests runner repository", exact: true })
).toBeVisible();
});
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
sizes="16x16"
href="/icons/favicon-16x16.png"
/>
<link rel="preload" href="/images/hero-education-image.svg" as="image" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
Expand Down
1 change: 1 addition & 0 deletions public/images/hero-education-image.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/images/programmers-image.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/screenshots/courses-list.webp
Binary file not shown.
Binary file added public/images/screenshots/grading-view.webp
Binary file not shown.
Binary file not shown.
Binary file added public/images/screenshots/laboratory-view.webp
Binary file not shown.
Binary file added public/images/screenshots/rubric-view.webp
Binary file not shown.
Binary file added public/images/screenshots/statistics-view.webp
Binary file not shown.
12 changes: 0 additions & 12 deletions src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,6 @@ const source = [
{
name: "Organization profile",
url: "https://github.com/upb-code-labs"
},
{
name: "Frontend repository",
url: "https://github.com/UPB-Code-Labs/react-client"
},
{
name: "Main API repository",
url: "https://github.com/UPB-Code-Labs/main-api"
},
{
name: "Tests runner repository",
url: "https://github.com/UPB-Code-Labs/tests-microservice"
}
];

Expand Down
2 changes: 1 addition & 1 deletion src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { CourseParticipants } from "@/screens/course-page/participants/CoursePar
import { CoursesHome } from "@/screens/courses-list/CoursesHome";
import { EditLaboratory } from "@/screens/edit-laboratory/EditLaboratory";
import { EditRubricView } from "@/screens/edit-rubric/EditRubricView";
import { Home } from "@/screens/home/Home";
import { ProfileView } from "@/screens/profile/ProfileView";
import { RubricsHome } from "@/screens/rubrics-list/RubricsHome";
import { FormContainer } from "@/screens/session/FormContainer";
Expand All @@ -23,7 +24,6 @@ import { RegisterStudentForm } from "@/screens/session/register-student/Form";
import { RegisterTeacherForm } from "@/screens/session/register-teacher/Form";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { Home } from "lucide-react";
import ReactDOM from "react-dom/client";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { Toaster } from "sonner";
Expand Down
3 changes: 0 additions & 3 deletions src/screens/Home.tsx

This file was deleted.

13 changes: 13 additions & 0 deletions src/screens/home/Home.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { HomeFeatures } from "./components/HomeFeatures";
import { HomeHeader } from "./components/HomeHeader";
import { OpenSourceSection } from "./components/OpenSourceSection";

export const Home = () => {
return (
<main>
<HomeHeader />
<HomeFeatures />
<OpenSourceSection />
</main>
);
};
36 changes: 36 additions & 0 deletions src/screens/home/components/HomeFeatures.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import features from "../data/features.json";

export const HomeFeatures = () => {
return (
<section className="bg-neutral-50">
<div className="mx-auto max-w-7xl px-4 py-8">
<h2 className="mb-8 text-3xl font-semibold">Main features</h2>
<div className="grid grid-cols-[repeat(auto-fill,minmax(320px,1fr))] gap-8">
{features.map((feature, index) => (
<article
key={`feature-${index}`}
className="group flex flex-col justify-between overflow-hidden rounded-lg border bg-white shadow-sm transition-shadow hover:shadow-xl"
>
<div className="space-y-4 text-pretty p-8 pb-0">
<h3 className="text-2xl font-semibold text-neutral-700">
{feature.name}
</h3>
<p className="text-lg text-neutral-600">
{feature.description}
</p>
</div>
<img
src={feature.image}
alt={`${feature.name} screenshot`}
className="self-end transition-transform duration-500 group-hover:scale-125"
width={403}
height={302}
loading={index >= 3 ? "lazy" : "eager"}
/>
</article>
))}
</div>
</div>
</section>
);
};
21 changes: 21 additions & 0 deletions src/screens/home/components/HomeHeader.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.hero::after,
.hero::before {
content: "";
position: absolute;
width: 280px;
height: 280px;
background-color: #ae3dff;
filter: blur(64px) opacity(0.15);
border-radius: 50%;
z-index: -1;
}

.hero::before {
left: 0;
bottom: 0;
}

.hero::after {
right: 0;
top: 0;
}
70 changes: 70 additions & 0 deletions src/screens/home/components/HomeHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { buttonVariants } from "@/components/ui/button";
import { AuthContext } from "@/context/AuthContext";
import { useContext } from "react";
import { Link } from "react-router-dom";

import styles from "./HomeHeader.module.css";

export const HomeHeader = () => {
const { user } = useContext(AuthContext);

return (
<div className="px-4">
<header
className={`relative mx-auto my-8 max-w-7xl overflow-hidden rounded-3xl ${styles.hero}`}
>
{/* Hero content container */}
<div className="grid gap-8 p-8 md:grid-cols-2 md:p-12">
{/* Texts container */}
<div className="grid place-items-center">
<div className="flex max-w-prose flex-col items-center gap-4 text-pretty text-center md:items-start md:text-start">
<h1 className="text-3xl font-bold !leading-snug sm:text-4xl md:text-5xl">
Simplify learning through{" "}
<span className="text-purple-upb">
programming learning activities
</span>
</h1>
<p className="text-xl leading-relaxed text-black/75">
With Code Labs, students receive instant feedback, while
educators enjoy simplified grading and monitoring in coding
activities.
</p>
<div>
{user ? (
<Link
to="/courses"
className={buttonVariants({
variant: "default",
size: "lg"
})}
>
Go to courses
</Link>
) : (
<Link
to="/register/students"
className={buttonVariants({
variant: "default",
size: "lg"
})}
>
Get started
</Link>
)}
</div>
</div>
</div>
{/* Image container */}
<div className="grid place-items-center">
<img
src="/images/hero-education-image.svg"
alt="A student with a graduation cap on top of a book"
className="w-full max-w-sm md:max-w-full xl:max-w-[75%]"
loading="eager"
/>
</div>
</div>
</header>
</div>
);
};
61 changes: 61 additions & 0 deletions src/screens/home/components/OpenSourceSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { BugIcon, GitPullRequestArrowIcon, SearchIcon } from "lucide-react";

export const OpenSourceSection = () => {
const actions = [
{
text: "Walk through / audit the source code",
icon: SearchIcon
},
{
text: "Report bugs or issues",
icon: BugIcon
},
{
text: "Submit pull requests",
icon: GitPullRequestArrowIcon
}
];

return (
<section
className="mx-auto my-8 max-w-7xl px-4
"
>
<h2 className="mb-8 text-3xl font-semibold">
We're an open source project
</h2>
<div className="grid gap-8 md:grid-cols-2">
{/* Text container*/}
<div className="space-y-4 text-pretty text-lg">
<p className="max-w-prose">
We believe that making Code Labs an open source project will help us
to build, maintain, and evolve the project as more people from our
university community involve themselves in the project. Feel free
to:
</p>
<ul className="flex flex-col gap-4">
{actions.map((action, index) => (
<li key={`open-source-action-${index}`}>
<div className="flex items-center gap-4">
<span className="grid aspect-square place-items-center rounded-full bg-gradient-to-r from-red-upb to-purple-upb p-3">
<action.icon size={20} color="white" />
</span>{" "}
{action.text}
</div>
</li>
))}
</ul>
</div>
{/* Image container*/}
<div className="grid place-items-center">
<img
src="/images/programmers-image.svg"
alt="Two programmers working on a project"
className="w-full max-w-sm md:max-w-[75%]"
loading="lazy"
/>
</div>
</div>
</section>
);
};
32 changes: 32 additions & 0 deletions src/screens/home/data/features.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[
{
"name": "Simple design inspired by well-know platforms",
"description": "Our design is inspired by widely-used platforms in the university community, ensuring a user-friendly experience without a steep learning curve.",
"image": "/images/screenshots/courses-list.webp"
},
{
"name": "Create labs with Markdown instructions and unit tests",
"description": "Write lab instructions with the widely-used Markdown language, and integrate unit tests—all within the same platform.",
"image": "/images/screenshots/laboratory-view.webp"
},
{
"name": "\"Real time\" feedback for students",
"description": "Using Server Sent Events (SSE), students can receive feedback on their code in \"real time\".",
"image": "/images/screenshots/laboratory-feedback.webp"
},
{
"name": "Transparent grading system with rubrics",
"description": "Professors must create rubrics for objective assessment, ensuring a systematic and transparent grading process and empowering students with detailed feedback.",
"image": "/images/screenshots/rubric-view.webp"
},
{
"name": "Insightful student performance metrics",
"description": "Professors can visualize student progress with detailed charts, including the number of completed, pending and failed tests per student and group averages.",
"image": "/images/screenshots/statistics-view.webp"
},
{
"name": "Simplified grading process",
"description": "Professors can grade students' labs by using their rubrics, provide feedback and download the students' code for further review.",
"image": "/images/screenshots/grading-view.webp"
}
]
4 changes: 3 additions & 1 deletion src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ export async function downloadLanguageTemplate(
return;
}

const joinedLanguageName = languageName.split(" ").join("-");

downloadBlob({
file: template,
fileName: `${languageName.toLowerCase()}-template.zip`
fileName: `${joinedLanguageName.toLowerCase()}-template.zip`
});
}

Expand Down

0 comments on commit 254b541

Please sign in to comment.