Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
8 changes: 4 additions & 4 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
"name": "frontend",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"codegen": "graphql-codegen",
"codegen": "graffle generate --schema http://localhost:1337/graphql --output src/graffle",
"prepare": "cd .. && husky frontend/.husky"
},
"dependencies": {
"@opentelemetry/api": "^1.9.0",
"es-toolkit": "^1.25.2",
"graffle": "^8.0.0-next.75",
"clsx": "^2.1.1",
"graphql": "^16.9.0",
"graphql-request": "^7.1.0",
"next": "14.2.8",
"react": "^18",
"react-dom": "^18"
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";

import clsx from "clsx";

interface IButton {
children: React.ReactNode;
onClick?: () => void;
className?: string;
}

const Button: React.FC<IButton> = ({ children, onClick, className }) => (
<button
className={clsx("bg-primary-blue py-2 px-8 rounded-full", className)}
{...{ onClick }}
>
{children}
</button>
);

export default Button;
84 changes: 71 additions & 13 deletions frontend/src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,83 @@
import React from "react";

import clsx from "clsx";
import Image from "next/image";
import Link from "next/link";

import { socialsQueryType } from "@/queries/socials";
import Button from "@/components/Button";
import { FooterQueryType } from "@/queries/footer";

const hoverScaleUp = clsx("hover:scale-105 transform transition duration-75");

interface IFooter {
socials: socialsQueryType["socials"];
footerData: FooterQueryType;
}

const Footer: React.FC<IFooter> = ({ socials }) => {
const Footer: React.FC<IFooter> = ({ footerData }) => {
const socials = footerData.footerSocialsSection.socials;
const sections = footerData.footerLinksSection.Section;
const cta = footerData.footerSubscribeCta;
return (
<div className={
"py-4 bg-gradient-to-b from-secondary-blue to-30% to-primary-purple"
}>
<hr className="h-0.5 border-t-0 bg-secondary-purple mb-4 mx-2"/>
<div className="flex gap-4 justify-center align-middle">
{socials.map(({ name, icon }) => (
<div key={name}>
<Image src={icon.url} alt={name} width="24" height="24" />
</div>
))}
<div>
<div className={
clsx([
"bg-gradient-to-b from-secondary-blue to-[27.74%] to-primary-purple",
"py-16"
])
}>
<div className="flex flex-col gap-12 px-6">
{sections.map(({ title, links }) => (
<div key={title} className="flex flex-col gap-4">
<h1 className="text-background-2">
{title}
</h1>
{links.map(({ name, url }) => (
<Link
className={clsx(hoverScaleUp, "w-max")}
key={name}
href={url}
target={url.trim().startsWith("http") ? "_blank" : ""}
rel="noopener noreferrer"
>
{name}
</Link>
))}
</div>
))}
</div>
<hr className="h-0.5 border-t-0 bg-secondary-purple mt-16 mb-6 mx-6"/>
<div className="flex gap-8 justify-center items-center">
{socials.map(({ name, icon_white: icon, url }) => (
<Link
className={hoverScaleUp}
key={name}
href={url}
target="_blank"
rel="noopener noreferrer"
>
<Image src={icon.url} alt={name} width="24" height="24" />
</Link>
))}
</div>
</div>
<div
className={clsx(
["flex flex-col justify-center items-center"],
["bg-background-2 py-16"],
)}
>
<Image
src={cta.logo.url}
alt="kleros logo"
width="185"
height="48"
className="mb-8"
/>
<p className="mb-8">{cta.notice}</p>
<p className="mb-6">{cta.cta_text}</p>
<Button>
<p className="text-background-2">{cta.cta_button}</p>
</Button>
</div>
</div>
);
Expand Down
38 changes: 38 additions & 0 deletions frontend/src/components/TrustedBy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react";

import Image from "next/image";

import { PartnersQueryType } from "@/queries/partners";

interface ITrustedBy {
partnersData: PartnersQueryType
}

const TrustedBy: React.FC<ITrustedBy> = ({ partnersData }) => {
const partners = partnersData.partners;
return (
<div className="bg-background-2 py-4 px-6">
<p className="text-2xl mx-auto w-max mb-2 text-secondary-text">
Trusted By
</p>
<div className="flex gap-2">
{partners.map(({ name, icon_svg }) =>
<div
key={name}
className={
"bg-white h-16 w-16 rounded-full flex justify-center items-center"
}
>
<Image
src={icon_svg.url}
alt={name}
width="42"
height="42"
/>
</div>
)}
</div>
</div>
)
}
export default TrustedBy;
25 changes: 14 additions & 11 deletions frontend/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
import Footer from "@/components/Footer";
import TrustedBy from "@/components/TrustedBy";
import { partnersQuery, partnersQueryType } from "@/queries/partners";
import { socialsQuery, socialsQueryType } from "@/queries/socials";
import { footerQuery, FooterQueryType } from "@/queries/footer";
import { partnersQuery, PartnersQueryType } from "@/queries/partners";
import { graphQLClient } from "@/utils/graphQLClient";

interface IHome {
partners: partnersQueryType["partners"];
socials: socialsQueryType["socials"];
partnersData: PartnersQueryType;
footerData: FooterQueryType;
}

const Home: React.FC<IHome> = ({ partners, socials }) => {
const Home: React.FC<IHome> = ({ partnersData, footerData }) => {
return (
<div>
<TrustedBy {...{ partners }}/>
<Footer {...{ socials }}/>
<TrustedBy {...{ partnersData }}/>
<Footer {...{ footerData }}/>
</div>
);
}

export const getStaticProps = async () => {
const { partners } = await partnersQuery.run();
const { socials } = await socialsQuery.run();
const partnersData = await graphQLClient.request<PartnersQueryType>(
partnersQuery
);
const footerData = await graphQLClient.request<FooterQueryType>(footerQuery);
return {
props: {
partners,
socials,
partnersData,
footerData,
}
};
};
Expand Down
61 changes: 61 additions & 0 deletions frontend/src/queries/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { gql } from "graphql-request";

export const footerQuery = gql`
{
footerLinksSection {
Section {
title
links {
name
url
}
}
}
footerSocialsSection {
socials {
name,
url,
icon_white {
url
}
}
}
footerSubscribeCta {
logo {
url
}
notice
cta_text
cta_button
}
}
`;

export type FooterQueryType = {
footerLinksSection: {
Section: {
title: string,
links: {
name: string,
url: string,
}[],
}[],
},
footerSocialsSection: {
socials: {
name: string,
url: string,
icon_white: {
url: string
},
}[],
},
footerSubscribeCta: {
logo: {
url: string
},
notice: string,
cta_text: string,
cta_button: string,
},
};
21 changes: 21 additions & 0 deletions frontend/src/queries/partners.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { gql } from "graphql-request";

export const partnersQuery = gql`
{
partners {
name
icon_svg {
url
}
}
}
`;

export type PartnersQueryType = {
partners: {
name: string,
icon_svg: {
url: string
}
}[]
};
15 changes: 8 additions & 7 deletions frontend/src/utils/graphQLClient.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Graffle } from "@/graffle/__.js";
import { GraphQLClient } from "graphql-request";

import { getStrapiURL } from "@/utils/getStrapiURL";

const endpoint = getStrapiURL("/graphql");

const token = process.env.STRAPI_TOKEN;

export const graffle = Graffle.create({
schema: endpoint,
transport: {
headers: { Authorization: `Bearer ${token}` },
},
});
export const graphQLClient = new GraphQLClient(
endpoint,
{
headers: { Authorization: `Bearer ${token}` }
}
);

Loading