Skip to content

Commit 33f8edb

Browse files
Clean version of project for NextJS lesson
0 parents  commit 33f8edb

31 files changed

+3081
-0
lines changed

Diff for: .babelrc

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"presets": [
3+
"next/babel"
4+
],
5+
"plugins": [
6+
[
7+
"styled-components",
8+
{
9+
"ssr": true,
10+
"displayName": true
11+
}
12+
]
13+
]
14+
}

Diff for: .env.local

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
NEXT_PUBLIC_RICK_API_URL=https://rickandmortyapi.com/api
2+
NEXT_PUBLIC_API_URL=http://localhost:3000/api
3+
NEXT_PUBLIC_SECRET_TOKEN=KfILnCKwQLCd

Diff for: .eslintrc.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

Diff for: .gitignore

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
#.env*.local
29+
# let .env file to be available on github for lesson purpose
30+
31+
# vercel
32+
.vercel
33+
34+
# typescript
35+
*.tsbuildinfo
36+
next-env.d.ts
37+
38+
/.idea

Diff for: README.md

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2+
3+
## Getting Started
4+
5+
First, run the development server:
6+
7+
```bash
8+
npm run dev
9+
# or
10+
yarn dev
11+
# or
12+
pnpm dev
13+
```
14+
15+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
16+
17+
### @stacy_imladris
18+
19+
### Have fun! :)

Diff for: assets/api/api.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { instance, instanceRick } from "./instances";
2+
import { RickAndMortyApi } from "./rick-and-morty-api";
3+
import { NextJsApi } from "./next-js-api";
4+
5+
const rickAndMortyApi = new RickAndMortyApi(instanceRick);
6+
const nextJsApi = new NextJsApi(instance);
7+
8+
export const API = {
9+
rickAndMorty: rickAndMortyApi,
10+
nextJs: nextJsApi,
11+
};

Diff for: assets/api/instances.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import axios from "axios";
2+
3+
/**
4+
* Instance for NextJS API
5+
*/
6+
export const instance = axios.create({
7+
baseURL: process.env.NEXT_PUBLIC_API_URL,
8+
});
9+
10+
/**
11+
* Instance for Rick and Morty API
12+
*/
13+
export const instanceRick = axios.create({
14+
baseURL: process.env.NEXT_PUBLIC_RICK_API_URL,
15+
});

Diff for: assets/api/next-js-api.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import {AxiosInstance} from 'axios';
2+
3+
export class NextJsApi {
4+
constructor(private instance: AxiosInstance) {}
5+
}

Diff for: assets/api/rick-and-morty-api.ts

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { AxiosInstance } from "axios";
2+
import {Nullable} from '../types/Nullable';
3+
4+
export class RickAndMortyApi {
5+
constructor(private instance: AxiosInstance) {}
6+
7+
public getCharacters(params?: ParamsType) {
8+
return this.instance
9+
.get<ResponseType<CharacterType>>("/character", { params })
10+
.then((res) => res.data);
11+
}
12+
13+
public getCharacter(id: string) {
14+
return this.instance
15+
.get<CharacterType>(`/character/${id}`)
16+
.then((res) => res.data);
17+
}
18+
19+
public getLocations(params?: ParamsType) {
20+
return this.instance
21+
.get<ResponseType<LocationType>>("/location", { params })
22+
.then((res) => res.data);
23+
}
24+
25+
public getLocation(id: string) {
26+
return this.instance
27+
.get<LocationType>(`/location/${id}`)
28+
.then((res) => res.data);
29+
}
30+
31+
public getEpisodes(params?: ParamsType) {
32+
return this.instance
33+
.get<ResponseType<EpisodeType>>("/episode", { params })
34+
.then((res) => res.data);
35+
}
36+
37+
public getEpisode(id: string) {
38+
return this.instance
39+
.get<EpisodeType>(`/episode/${id}`)
40+
.then((res) => res.data);
41+
}
42+
}
43+
44+
/**
45+
* types
46+
*/
47+
export type ResponseType<T> = {
48+
info: InfoType;
49+
results: T[];
50+
};
51+
52+
type InfoType = {
53+
count: number;
54+
pages: number;
55+
next: Nullable<string>;
56+
prev: Nullable<string>;
57+
};
58+
59+
export type CharacterType = {
60+
id: number;
61+
name: string;
62+
status: CharacterStatusType;
63+
species: string;
64+
type: string;
65+
gender: CharacterGenderType;
66+
origin: ExtraDataType;
67+
location: ExtraDataType;
68+
image: string;
69+
episode: string[];
70+
url: string;
71+
created: string;
72+
};
73+
74+
export type LocationType = {
75+
id: number;
76+
name: string;
77+
type: string;
78+
dimension: string;
79+
residents: string[];
80+
url: string;
81+
created: string;
82+
};
83+
84+
export type EpisodeType = {
85+
id: number;
86+
name: string;
87+
air_date: string;
88+
episode: string;
89+
characters: string[];
90+
url: string;
91+
created: string;
92+
};
93+
94+
export type CharacterStatusType = "Alive" | "Dead" | "unknown";
95+
96+
type CharacterGenderType = "Female" | "Male" | "Genderless" | "unknown";
97+
98+
type ExtraDataType = {
99+
name: string;
100+
url: string;
101+
};
102+
103+
type ParamsType = {
104+
page: number;
105+
};

Diff for: assets/types/Nullable.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type Nullable<T> = T | null

Diff for: components/Card/Card.tsx

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { PropsWithChildren } from "react";
2+
import styled from "styled-components";
3+
4+
type PropsType = {
5+
name: string;
6+
};
7+
8+
export const Card = (props: PropsWithChildren<PropsType>) => {
9+
const { children, name } = props;
10+
11+
return (
12+
<CardBlock>
13+
<Name>{name}</Name>
14+
{children}
15+
</CardBlock>
16+
);
17+
};
18+
19+
const CardBlock = styled.div`
20+
display: flex;
21+
flex-direction: column;
22+
padding: 15px;
23+
border: 2px solid #facaff;
24+
box-shadow: 0 2px 3px 1px #fa52d3;
25+
border-radius: 15px;
26+
`;
27+
28+
const Name = styled.div`
29+
font-weight: 600;
30+
font-size: 24px;
31+
`;

Diff for: components/Card/CharacterCard/CharacterCard.tsx

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Card } from "../Card";
2+
import styled from "styled-components";
3+
import Image from "next/image";
4+
import Link from "next/link";
5+
import aliveStatus from "public/statuses/alive.png";
6+
import deadStatus from "public/statuses/dead.png";
7+
import unknownStatus from "public/statuses/unknown.png";
8+
import {CharacterType} from '../../../assets/api/rick-and-morty-api';
9+
10+
const statusImages = {
11+
Alive: aliveStatus,
12+
Dead: deadStatus,
13+
unknown: unknownStatus,
14+
};
15+
16+
type PropsType = {
17+
character: CharacterType;
18+
};
19+
20+
export const CharacterCard = (props: PropsType) => {
21+
const { id, name, image, status } = props.character;
22+
23+
return (
24+
<Card name={name}>
25+
<Link href={`/characters/${id}`}>
26+
<ImageBlock src={image} alt={name} width={300} height={300} priority />
27+
</Link>
28+
</Card>
29+
);
30+
};
31+
32+
const ImageBlock = styled(Image)`
33+
object-fit: cover;
34+
`;

Diff for: components/HeadMeta/HeadMeta.tsx

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Head from "next/head";
2+
3+
type PropsType = {
4+
title?: string;
5+
};
6+
7+
export const HeadMeta = (props: PropsType) => {
8+
const { title } = props;
9+
10+
const description = title
11+
? `Rick and Morty ${title.toLowerCase()}`
12+
: "Master class for IT-incubator";
13+
14+
return (
15+
<Head>
16+
<title>{title ?? "NextJS Master Class"}</title>
17+
<meta name="description" content={description} />
18+
<link rel="icon" href="/favicon.svg" />
19+
</Head>
20+
);
21+
};

Diff for: components/Header/Header.tsx

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import styled from 'styled-components';
2+
import {LinkBlock} from './LinkBlock/LinkBlock';
3+
4+
export const Header = () => (
5+
<Navbar>
6+
<LinkBlock title={'Characters'}/>
7+
<LinkBlock title={'Locations'}/>
8+
<LinkBlock title={'Episodes'}/>
9+
</Navbar>
10+
)
11+
12+
const Navbar = styled.div`
13+
display: flex;
14+
justify-content: center;
15+
width: 1280px;
16+
max-width: 100%;
17+
margin: 0 auto;
18+
19+
@media (max-width: 700px) {
20+
flex-direction: column;
21+
text-align: center;
22+
}
23+
`

Diff for: components/Header/LinkBlock/LinkBlock.tsx

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import Link from "next/link";
2+
import styled from "styled-components";
3+
4+
type PropsType = {
5+
title: string;
6+
};
7+
8+
export const LinkBlock = (props: PropsType) => {
9+
const { title } = props;
10+
11+
return (
12+
<LinkWrapper>
13+
<Link href={`/${title.toLowerCase()}`}>
14+
<h2>{title}</h2>
15+
</Link>
16+
</LinkWrapper>
17+
);
18+
};
19+
20+
const LinkWrapper = styled.div`
21+
padding: 20px;
22+
border-radius: 12px;
23+
border: 1px solid rgba(131, 134, 135, 0);
24+
25+
& h2 {
26+
font-weight: 600;
27+
font-size: 28px;
28+
margin-bottom: 0.7rem;
29+
}
30+
31+
@media (max-width: 700px) {
32+
padding: 4px;
33+
34+
& h2 {
35+
font-weight: 600;
36+
font-size: 24px;
37+
}
38+
}
39+
`;

0 commit comments

Comments
 (0)