Skip to content
This repository was archived by the owner on Jan 19, 2025. It is now read-only.

Commit 9e39f28

Browse files
authored
API - first attempt (#128)
* First api attempt creation 🚀 * First api almost completed 🚀 * Authors api 🚀 * Added resource endpoint * Added web endpoint (first iteration probably webview) * Fix articles 🚀 * Refactoring projects 🚀 * Refactoring api images query: select all the ones needed in a single query 🚀 * Projects api completed 🚀 * Implemented art api 🚀 * Fix tests 🚀
1 parent b893220 commit 9e39f28

27 files changed

+627
-432
lines changed

.idea/prettier.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

__tests__/call-to-action-external-with-tracking.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import React from "react";
21
import { fireEvent, render, screen } from "@testing-library/react";
32
import { trackWith } from "../src/logic/tracking";
43
import { BlogThemePage } from "../src/components/design-system/templates/blog-theme-page";

__tests__/call-to-action-internal-with-tracking.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import React from "react";
21
import { fireEvent, render, screen } from "@testing-library/react";
32
import { CallToActionInternalWithTracking } from "../src/components/call-to-action-internal-with-tracking";
43
import { trackWith } from "../src/logic/tracking";

__tests__/resume.test.tsx

Lines changed: 0 additions & 25 deletions
This file was deleted.

__tests__/standard-external-link-with-tracking.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import React from "react";
21
import { fireEvent, render, screen } from "@testing-library/react";
32
import { trackWith } from "../src/logic/tracking";
43
import { BlogThemePage } from "../src/components/design-system/templates/blog-theme-page";

__tests__/standard-internal-link-with-tracking.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import React from "react";
21
import { fireEvent, render, screen } from "@testing-library/react";
32
import { trackWith } from "../src/logic/tracking";
43
import { BlogThemePage } from "../src/components/design-system/templates/blog-theme-page";

gatsby-node.ts

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
import { GatsbyNode } from "gatsby";
22
import readingTime from "reading-time";
33
import * as path from "path";
4+
import * as fs from "fs";
45
import { createFilePath } from "gatsby-source-filesystem";
56
import { generatePostSlug, generateTagSlug, slugs } from "./src/logic/slug";
7+
import {
8+
artApiAdapter,
9+
blogAuthorsApiAdapter,
10+
blogPostDetailsApiAdapter,
11+
blogPostsApiAdapter,
12+
projectsApiAdapter
13+
} from "./src/logic/api/api-adapters";
614

715
export const createPages: GatsbyNode["createPages"] = async ({
816
graphql,
917
actions,
1018
reporter,
1119
}) => {
1220
const { createPage } = actions;
13-
const result: any = await graphql(`
21+
const result = await graphql<Queries.BlogPostsQuery>(`
1422
query BlogPosts {
1523
allMarkdownRemark(sort: { frontmatter: { date: DESC } }, limit: 1000) {
1624
edges {
@@ -34,7 +42,7 @@ export const createPages: GatsbyNode["createPages"] = async ({
3442
return;
3543
}
3644

37-
const posts = result.data.allMarkdownRemark.edges;
45+
const posts = result.data!.allMarkdownRemark.edges;
3846

3947
//Create posts pages
4048
posts.forEach((post: any) => {
@@ -47,7 +55,7 @@ export const createPages: GatsbyNode["createPages"] = async ({
4755
});
4856
});
4957

50-
// Create blog home pages
58+
// Create blog home (paginated) pages
5159
const postsPerPage = 11;
5260
const numberOfPages = Math.ceil(posts.length / postsPerPage);
5361
Array.from({ length: numberOfPages }).forEach((_, i) => {
@@ -64,7 +72,7 @@ export const createPages: GatsbyNode["createPages"] = async ({
6472
});
6573

6674
//Create tag pages
67-
const tags: any = result.data.tagsGroup.group;
75+
const tags: any = result.data!.tagsGroup.group;
6876
tags.forEach((tag: any) => {
6977
createPage({
7078
path: generateTagSlug(tag.fieldValue),
@@ -92,3 +100,84 @@ export const onCreateNode: GatsbyNode["onCreateNode"] = ({
92100
});
93101
}
94102
};
103+
104+
export const onPostBuild: GatsbyNode["onPostBuild"] = async ({ graphql }) => {
105+
console.log("onPostBuild: generating API...");
106+
107+
const apiBasePath = "/api";
108+
const apiFolder = `./public${apiBasePath}`;
109+
110+
if (!fs.existsSync(apiFolder)) {
111+
fs.mkdirSync(apiFolder);
112+
}
113+
114+
const blogPostsQuery = (
115+
await graphql<Queries.BlogPostsApiQuery>(`
116+
query BlogPostsApi {
117+
allMarkdownRemark(sort: { frontmatter: { date: DESC } }, limit: 1000) {
118+
edges {
119+
node {
120+
fields {
121+
slug
122+
readingTime {
123+
text
124+
}
125+
}
126+
frontmatter {
127+
title
128+
description
129+
authors
130+
tags
131+
math
132+
date(formatString: "DD MMM YYYY")
133+
image {
134+
publicURL
135+
}
136+
}
137+
html
138+
}
139+
}
140+
}
141+
}
142+
`)
143+
).data!;
144+
145+
const imagesApiQuery = (
146+
await graphql<Queries.ImagesApiQuery>(`
147+
query ImagesApi {
148+
allFile(
149+
filter: {
150+
relativeDirectory: { in: ["projects", "authors", "art"] }
151+
extension: { regex: "/(jpg)|(jpeg)|(png)/" }
152+
}
153+
) {
154+
edges {
155+
node {
156+
publicURL
157+
name
158+
}
159+
}
160+
}
161+
}
162+
`)
163+
).data!;
164+
165+
const blogPostsApi = blogPostsApiAdapter(apiBasePath, blogPostsQuery);
166+
const authorsApi = blogAuthorsApiAdapter(imagesApiQuery);
167+
const blogPostDetailApis = blogPostDetailsApiAdapter(blogPostsQuery);
168+
const projectsApi = projectsApiAdapter(imagesApiQuery);
169+
const artApi = artApiAdapter(imagesApiQuery);
170+
171+
fs.writeFileSync(`${apiFolder}/posts.json`, JSON.stringify(blogPostsApi));
172+
fs.writeFileSync(`${apiFolder}/authors.json`, JSON.stringify(authorsApi));
173+
Object.keys(blogPostDetailApis).forEach((key) => {
174+
fs.writeFileSync(
175+
`${apiFolder}/${key}.json`,
176+
JSON.stringify(blogPostDetailApis[key]),
177+
);
178+
});
179+
fs.writeFileSync(`${apiFolder}/projects.json`, JSON.stringify(projectsApi));
180+
fs.writeFileSync(`${apiFolder}/art.json`, JSON.stringify(artApi));
181+
182+
console.log("onPostBuild: API generation completed.");
183+
};

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,12 @@
3131
"node": "^18.4.0"
3232
},
3333
"scripts": {
34+
"prestart": "npm run clean",
3435
"start": "gatsby develop",
3536
"clean": "gatsby clean",
3637
"serve": "gatsby serve",
3738
"test": "jest",
38-
"prebuild": "npm run test",
39+
"prebuild": "npm run clean",
3940
"build": "gatsby build",
4041
"predeploy": "npm run clean && npm run build",
4142
"deploy": "gh-pages -d public -b main"

src/components/design-system/molecules/post-authors.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export const PostAuthors: FC<PostAuthorsProps> = ({
7878
const blogAuthor: BlogAuthor = blogAuthors[author!];
7979
const blogAuthorImage = blogAuthorsImages.allFile.edges.find(
8080
(blogAuthorImage) =>
81-
blogAuthorImage.node.name === author!.replace("_", "-")
81+
blogAuthorImage.node.name === author!.split("_").join("-"),
8282
)!.node!.childImageSharp!.gatsbyImageData!;
8383

8484
return (

src/components/design-system/molecules/project.tsx

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import styled from "styled-components";
44
import { Container } from "../atoms/container";
55
import { CallToActionExternalWithTracking } from "../../call-to-action-external-with-tracking";
66
import { mediaQuery } from "../utils-css/media-query";
7+
import { ProjectCallToAction } from "../../../logic/projects";
8+
import { Paragraph } from "../atoms/paragraph";
9+
import { List } from "../atoms/list";
10+
import { GatsbyImage, IGatsbyImageData } from "gatsby-plugin-image";
711

812
interface ProjectContainerProps {
913
reverse: boolean;
@@ -32,22 +36,15 @@ const ProjectImageContainer = styled(ProjectContentContainer)`
3236
align-items: center;
3337
`;
3438

35-
interface ProjectCallToAction {
36-
label: string;
37-
link: string;
38-
trackingAction: string;
39-
trackingCategory: string;
40-
trackingLabel: string;
41-
}
42-
4339
const CallToActionContainer = styled.div`
4440
margin: ${(props) => props.theme.spacing[6]} 0;
4541
`;
4642

4743
export type ProjectProps = ProjectContainerProps & {
4844
name: string;
49-
image: React.ReactElement;
50-
description: React.ReactElement;
45+
image: IGatsbyImageData;
46+
description: string;
47+
features: string[];
5148
callToActions: ProjectCallToAction[];
5249
};
5350

@@ -56,13 +53,28 @@ export const Project: FC<ProjectProps> = ({
5653
name,
5754
image,
5855
description,
56+
features,
5957
callToActions,
6058
}) => (
6159
<ProjectContainer reverse={reverse}>
62-
<ProjectImageContainer>{image}</ProjectImageContainer>
60+
<ProjectImageContainer>
61+
<GatsbyImage
62+
style={{
63+
width: 500,
64+
height: 500,
65+
}}
66+
alt={name}
67+
image={image}
68+
/>
69+
</ProjectImageContainer>
6370
<ProjectContentContainer>
6471
<Heading3>{name}</Heading3>
65-
{description}
72+
<Paragraph>{description}</Paragraph>
73+
<List className="project-features">
74+
{features.map((feature) => (
75+
<li key={`${name}${feature}`}>{feature}</li>
76+
))}
77+
</List>
6678
<CallToActionContainer>
6779
{callToActions.map((callToAction) => (
6880
<CallToActionExternalWithTracking

0 commit comments

Comments
 (0)