Skip to content

Commit 1134454

Browse files
authored
Merge pull request #11 from kleros/feat(frontend)/add-footer
Feat(frontend): add footer and revert graffle to graph-ql
2 parents 9af616c + adfbb8a commit 1134454

File tree

9 files changed

+276
-86
lines changed

9 files changed

+276
-86
lines changed

frontend/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22
"name": "frontend",
33
"version": "0.1.0",
44
"private": true,
5+
"type": "module",
56
"scripts": {
67
"dev": "next dev",
78
"build": "next build",
89
"start": "next start",
910
"lint": "next lint",
10-
"codegen": "graphql-codegen",
11+
"codegen": "graffle generate --schema http://localhost:1337/graphql --output src/graffle",
1112
"prepare": "cd .. && husky frontend/.husky"
1213
},
1314
"dependencies": {
14-
"@opentelemetry/api": "^1.9.0",
15-
"es-toolkit": "^1.25.2",
16-
"graffle": "^8.0.0-next.75",
15+
"clsx": "^2.1.1",
1716
"graphql": "^16.9.0",
17+
"graphql-request": "^7.1.0",
1818
"next": "14.2.8",
1919
"react": "^18",
2020
"react-dom": "^18"

frontend/src/components/Button.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from "react";
2+
3+
import clsx from "clsx";
4+
5+
interface IButton {
6+
children: React.ReactNode;
7+
onClick?: () => void;
8+
className?: string;
9+
}
10+
11+
const Button: React.FC<IButton> = ({ children, onClick, className }) => (
12+
<button
13+
className={
14+
clsx(
15+
"bg-primary-blue py-2 px-8 rounded-full",
16+
"hover:bg-primary-blue/90 transition duration-75",
17+
className)}
18+
{...{ onClick }}
19+
>
20+
{children}
21+
</button>
22+
);
23+
24+
export default Button;

frontend/src/components/Footer.tsx

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,83 @@
11
import React from "react";
22

3+
import clsx from "clsx";
34
import Image from "next/image";
5+
import Link from "next/link";
46

5-
import { socialsQueryType } from "@/queries/socials";
7+
import Button from "@/components/Button";
8+
import { FooterQueryType } from "@/queries/footer";
9+
10+
const hoverScaleUp = clsx("hover:scale-105 transform transition duration-75");
611

712
interface IFooter {
8-
socials: socialsQueryType["socials"];
13+
footerData: FooterQueryType;
914
}
1015

11-
const Footer: React.FC<IFooter> = ({ socials }) => {
16+
const Footer: React.FC<IFooter> = ({ footerData }) => {
17+
const socials = footerData.footerSocialsSection.socials;
18+
const sections = footerData.footerLinksSection.Section;
19+
const cta = footerData.footerSubscribeCta;
1220
return (
13-
<div className={
14-
"py-4 bg-gradient-to-b from-secondary-blue to-30% to-primary-purple"
15-
}>
16-
<hr className="h-0.5 border-t-0 bg-secondary-purple mb-4 mx-2"/>
17-
<div className="flex gap-4 justify-center align-middle">
18-
{socials.map(({ name, icon }) => (
19-
<div key={name}>
20-
<Image src={icon.url} alt={name} width="24" height="24" />
21-
</div>
22-
))}
21+
<div>
22+
<div className={
23+
clsx([
24+
"bg-gradient-to-b from-secondary-blue to-[27.74%] to-primary-purple",
25+
"py-16"
26+
])
27+
}>
28+
<div className="flex flex-col gap-12 px-6">
29+
{sections.map(({ title, links }) => (
30+
<div key={title} className="flex flex-col gap-4">
31+
<h2 className="text-background-2">
32+
{title}
33+
</h2>
34+
{links.map(({ name, url }) => (
35+
<Link
36+
className={clsx(hoverScaleUp, "w-max")}
37+
key={name}
38+
href={url}
39+
target={/^https?:\/\//.test(url) ? "_blank" : undefined}
40+
rel="noopener noreferrer"
41+
>
42+
{name}
43+
</Link>
44+
))}
45+
</div>
46+
))}
47+
</div>
48+
<hr className="h-0.5 border-t-0 bg-secondary-purple mt-16 mb-6 mx-6"/>
49+
<div className="flex gap-8 justify-center items-center">
50+
{socials.map(({ name, icon_white: icon, url }) => (
51+
<Link
52+
className={hoverScaleUp}
53+
key={name}
54+
href={url}
55+
target="_blank"
56+
rel="noopener noreferrer"
57+
>
58+
<Image src={icon.url} alt={name} width="24" height="24" />
59+
</Link>
60+
))}
61+
</div>
62+
</div>
63+
<div
64+
className={clsx(
65+
["flex flex-col justify-center items-center"],
66+
["bg-background-2 py-16"],
67+
)}
68+
>
69+
<Image
70+
src={cta.logo.url}
71+
alt="kleros logo"
72+
width="185"
73+
height="48"
74+
className="mb-8"
75+
/>
76+
<p className="mb-8">{cta.notice}</p>
77+
<p className="mb-6">{cta.cta_text}</p>
78+
<Button>
79+
<span className="text-background-2">{cta.cta_button}</span>
80+
</Button>
2381
</div>
2482
</div>
2583
);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React from "react";
2+
3+
import Image from "next/image";
4+
5+
import { PartnersQueryType } from "@/queries/partners";
6+
7+
interface ITrustedBy {
8+
partnersData: PartnersQueryType
9+
}
10+
11+
const TrustedBy: React.FC<ITrustedBy> = ({ partnersData }) => {
12+
const partners = partnersData.partners;
13+
return (
14+
<div className="bg-background-2 py-4 px-6">
15+
<p className="text-2xl mx-auto w-max mb-2 text-secondary-text">
16+
Trusted By
17+
</p>
18+
<div className="flex gap-2">
19+
{partners.map(({ name, icon_svg }) =>
20+
<div
21+
key={name}
22+
className={
23+
"bg-white h-16 w-16 rounded-full flex justify-center items-center"
24+
}
25+
>
26+
<Image
27+
src={icon_svg.url}
28+
alt={name}
29+
width="42"
30+
height="42"
31+
/>
32+
</div>
33+
)}
34+
</div>
35+
</div>
36+
)
37+
}
38+
export default TrustedBy;

frontend/src/pages/index.tsx

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,32 @@
11
import Footer from "@/components/Footer";
22
import TrustedBy from "@/components/TrustedBy";
3-
import { partnersQuery, partnersQueryType } from "@/queries/partners";
4-
import { socialsQuery, socialsQueryType } from "@/queries/socials";
3+
import { footerQuery, FooterQueryType } from "@/queries/footer";
4+
import { partnersQuery, PartnersQueryType } from "@/queries/partners";
5+
import { graphQLClient } from "@/utils/graphQLClient";
56

67
interface IHome {
7-
partners: partnersQueryType["partners"];
8-
socials: socialsQueryType["socials"];
8+
partnersData: PartnersQueryType;
9+
footerData: FooterQueryType;
910
}
1011

11-
const Home: React.FC<IHome> = ({ partners, socials }) => {
12+
const Home: React.FC<IHome> = ({ partnersData, footerData }) => {
1213
return (
1314
<div>
14-
<TrustedBy {...{ partners }}/>
15-
<Footer {...{ socials }}/>
15+
<TrustedBy {...{ partnersData }}/>
16+
<Footer {...{ footerData }}/>
1617
</div>
1718
);
1819
}
1920

2021
export const getStaticProps = async () => {
21-
const { partners } = await partnersQuery.run();
22-
const { socials } = await socialsQuery.run();
22+
const partnersData = await graphQLClient.request<PartnersQueryType>(
23+
partnersQuery
24+
);
25+
const footerData = await graphQLClient.request<FooterQueryType>(footerQuery);
2326
return {
2427
props: {
25-
partners,
26-
socials,
28+
partnersData,
29+
footerData,
2730
}
2831
};
2932
};

frontend/src/queries/footer.tsx

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { gql } from "graphql-request";
2+
3+
export const footerQuery = gql`
4+
{
5+
footerLinksSection {
6+
Section {
7+
title
8+
links {
9+
name
10+
url
11+
}
12+
}
13+
}
14+
footerSocialsSection {
15+
socials {
16+
name,
17+
url,
18+
icon_white {
19+
url
20+
}
21+
}
22+
}
23+
footerSubscribeCta {
24+
logo {
25+
url
26+
}
27+
notice
28+
cta_text
29+
cta_button
30+
}
31+
}
32+
`;
33+
34+
export type FooterQueryType = {
35+
footerLinksSection: {
36+
Section: {
37+
title: string,
38+
links: {
39+
name: string,
40+
url: string,
41+
}[],
42+
}[],
43+
},
44+
footerSocialsSection: {
45+
socials: {
46+
name: string,
47+
url: string,
48+
icon_white: {
49+
url: string
50+
},
51+
}[],
52+
},
53+
footerSubscribeCta: {
54+
logo: {
55+
url: string
56+
},
57+
notice: string,
58+
cta_text: string,
59+
cta_button: string,
60+
},
61+
};

frontend/src/queries/partners.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { gql } from "graphql-request";
2+
3+
export const partnersQuery = gql`
4+
{
5+
partners {
6+
name
7+
icon_svg {
8+
url
9+
}
10+
}
11+
}
12+
`;
13+
14+
export type PartnersQueryType = {
15+
partners: {
16+
name: string,
17+
icon_svg: {
18+
url: string
19+
}
20+
}[]
21+
};
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import { Graffle } from "@/graffle/__.js";
1+
import { GraphQLClient } from "graphql-request";
2+
23
import { getStrapiURL } from "@/utils/getStrapiURL";
34

45
const endpoint = getStrapiURL("/graphql");
56

67
const token = process.env.STRAPI_TOKEN;
78

8-
export const graffle = Graffle.create({
9-
schema: endpoint,
10-
transport: {
11-
headers: { Authorization: `Bearer ${token}` },
12-
},
13-
});
9+
export const graphQLClient = new GraphQLClient(
10+
endpoint,
11+
{
12+
headers: { Authorization: `Bearer ${token}` }
13+
}
14+
);
1415

0 commit comments

Comments
 (0)