├── src
├── App.jsx
├── App.css
├── main.jsx
├── components
│ ├── Loading.jsx
│ ├── MovieCard.jsx
│ ├── MovieComponent.jsx
│ └── Home.jsx
├── assets
│ └── react.svg
└── index.css
├── vite.config.js
├── .gitignore
├── index.html
├── package.json
└── public
└── vite.svg
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import Home from "./components/Home";
2 |
3 | const App = () => {
4 | return ;
5 | };
6 |
7 | export default App;
8 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .card {
9 | padding: 2em;
10 | }
11 |
12 | .read-the-docs {
13 | color: #888;
14 | }
15 |
--------------------------------------------------------------------------------
/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App";
4 | import "./index.css";
5 |
6 | ReactDOM.createRoot(document.getElementById("root")).render(
7 | <>
8 |
9 | >
10 | );
11 |
--------------------------------------------------------------------------------
/src/components/Loading.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Loading = () => {
4 | return (
5 |
11 | );
12 | };
13 |
14 | export default Loading;
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/components/MovieCard.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const MovieCard = ({ myData }) => {
4 | const { title, body, id } = myData;
5 | return (
6 |
7 |
8 |
{id}
9 |
{body.substr(0, 150)}
10 |
{title.substr(0, 15)}
11 |
12 |
13 | );
14 | };
15 |
16 | export default MovieCard;
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "infinitescroll",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "axios": "^1.2.2",
13 | "react": "^18.2.0",
14 | "react-dom": "^18.2.0"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.0.26",
18 | "@types/react-dom": "^18.0.9",
19 | "@vitejs/plugin-react": "^3.0.0",
20 | "vite": "^4.0.0"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/components/MovieComponent.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import MovieCard from "./MovieCard";
3 |
4 | const MovieComponent = ({ movieInfo }) => {
5 | return (
6 |
7 |
8 |
List of cards
9 |
10 | {movieInfo.map((curVal, id) => {
11 | return ;
12 | })}
13 |
14 |
15 |
16 | );
17 | };
18 |
19 | export default MovieComponent;
20 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/Home.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import Loading from "./Loading";
3 | import MovieComponent from "./MovieComponent";
4 |
5 | const Home = () => {
6 | const [card, setCard] = useState([]);
7 | const [page, setPage] = useState(1);
8 | const [loading, setLoading] = useState(true);
9 |
10 | const getCardData = async () => {
11 | const res = await fetch(
12 | `https://jsonplaceholder.typicode.com/posts?_limit=9&_page=${page}`
13 | );
14 | const data = await res.json();
15 | // console.log(data);
16 | setCard((prev) => [...prev, ...data]);
17 | setLoading(false);
18 | };
19 |
20 | useEffect(() => {
21 | getCardData();
22 | }, [page]);
23 |
24 | const handelInfiniteScroll = async () => {
25 | // console.log("scrollHeight" + document.documentElement.scrollHeight);
26 | // console.log("innerHeight" + window.innerHeight);
27 | // console.log("scrollTop" + document.documentElement.scrollTop);
28 | try {
29 | if (
30 | window.innerHeight + document.documentElement.scrollTop + 1 >=
31 | document.documentElement.scrollHeight
32 | ) {
33 | setLoading(true);
34 | setPage((prev) => prev + 1);
35 | }
36 | } catch (error) {
37 | console.log(error);
38 | }
39 | };
40 |
41 | useEffect(() => {
42 | window.addEventListener("scroll", handelInfiniteScroll);
43 | return () => window.removeEventListener("scroll", handelInfiniteScroll);
44 | }, []);
45 |
46 | return (
47 | <>
48 |
49 | {loading && }
50 | >
51 | );
52 | };
53 |
54 | export default Home;
55 |
--------------------------------------------------------------------------------
/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300&family=Nunito:ital,wght@0,400;0,700;1,600&family=Work+Sans:wght@300;400;700;900&display=swap");
2 |
3 | :root {
4 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
5 | font-size: 16px;
6 | line-height: 24px;
7 | font-weight: 400;
8 |
9 | color-scheme: light dark;
10 | color: rgba(255, 255, 255, 0.87);
11 | background-color: #242424;
12 |
13 | font-synthesis: none;
14 | text-rendering: optimizeLegibility;
15 | -webkit-font-smoothing: antialiased;
16 | -moz-osx-font-smoothing: grayscale;
17 | -webkit-text-size-adjust: 100%;
18 | }
19 |
20 | html {
21 | font-size: 62.85%;
22 | font-family: "Cormorant Garamond", serif;
23 | }
24 |
25 | a {
26 | font-weight: 500;
27 | color: #646cff;
28 | text-decoration: inherit;
29 | }
30 | a:hover {
31 | color: #535bf2;
32 | }
33 |
34 | h1 {
35 | font-size: 3.2em;
36 | line-height: 1.1;
37 | font-family: "Cormorant Garamond", serif;
38 | text-transform: uppercase;
39 | text-align: center;
40 | margin: 5rem auto;
41 | }
42 |
43 | button {
44 | border-radius: 8px;
45 | border: 1px solid transparent;
46 | padding: 0.6em 1.2em;
47 | font-size: 1em;
48 | font-weight: 500;
49 | font-family: inherit;
50 | background-color: #1a1a1a;
51 | cursor: pointer;
52 | transition: border-color 0.25s;
53 | }
54 | button:hover {
55 | border-color: #646cff;
56 | }
57 | button:focus,
58 | button:focus-visible {
59 | outline: 4px auto -webkit-focus-ring-color;
60 | }
61 |
62 | .wrapper {
63 | width: 100%;
64 | /* margin: 0 auto; */
65 | }
66 | .container {
67 | /* background-color: red; */
68 | max-width: 80%;
69 | margin: 0 auto;
70 | }
71 |
72 | .grid {
73 | display: grid;
74 | gap: 3.2rem;
75 | }
76 | .grid-three-column {
77 | grid-template-columns: repeat(3, 1fr);
78 | }
79 |
80 | .card {
81 | /* background-color: #535bf2; */
82 | padding: 0 3.2rem;
83 | display: flex;
84 | flex-direction: column;
85 | justify-content: center;
86 | align-items: center;
87 | }
88 |
89 | .card-info {
90 | padding: 1rem 2rem;
91 | border-radius: 1rem;
92 | background-color: #213547;
93 | text-align: center;
94 | }
95 | @media screen and (max-width: 1119px) {
96 | .container {
97 | max-width: 90%;
98 | }
99 | .grid {
100 | gap: 1.6rem;
101 | }
102 |
103 | .card {
104 | background-color: #213547;
105 | }
106 | .card-info {
107 | padding: 0rem;
108 | background-color: #213547;
109 | }
110 | }
111 |
112 | .card-id {
113 | width: 3rem;
114 | height: 3rem;
115 | border-radius: 50%;
116 | color: #000;
117 | display: flex;
118 | justify-content: center;
119 | align-items: center;
120 | background-color: #fff;
121 | font-size: 1.6rem;
122 | }
123 |
124 | p {
125 | text-align: justify;
126 | font-family: "Cormorant Garamond", serif;
127 | font-size: 1.4rem;
128 | line-height: 1.6rem;
129 | }
130 | h2 {
131 | padding: 1rem;
132 | background-color: #0e0f0f;
133 | text-align: left;
134 | font-family: "Cormorant Garamond", serif;
135 | text-transform: capitalize;
136 | }
137 |
138 | figure {
139 | height: 15rem;
140 | display: grid;
141 | place-items: center;
142 | }
143 | img {
144 | max-width: 100%;
145 | height: inherit;
146 | }
147 |
148 | .loading-container {
149 | width: 100%;
150 | text-align: center;
151 | margin: 2rem auto;
152 | }
153 |
154 | .lds-ripple {
155 | display: inline-block;
156 | position: relative;
157 | width: 80px;
158 | height: 80px;
159 | }
160 | .lds-ripple div {
161 | position: absolute;
162 | border: 4px solid rgb(63, 219, 144);
163 | opacity: 1;
164 | border-radius: 50%;
165 | animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
166 | }
167 | .lds-ripple div:nth-child(2) {
168 | animation-delay: -0.5s;
169 | }
170 | @keyframes lds-ripple {
171 | 0% {
172 | top: 36px;
173 | left: 36px;
174 | width: 0;
175 | height: 0;
176 | opacity: 0;
177 | }
178 | 4.9% {
179 | top: 36px;
180 | left: 36px;
181 | width: 0;
182 | height: 0;
183 | opacity: 0;
184 | }
185 | 5% {
186 | top: 36px;
187 | left: 36px;
188 | width: 0;
189 | height: 0;
190 | opacity: 1;
191 | }
192 | 100% {
193 | top: 0px;
194 | left: 0px;
195 | width: 72px;
196 | height: 72px;
197 | opacity: 0;
198 | }
199 | }
200 |
201 | @media (prefers-color-scheme: light) {
202 | :root {
203 | color: #213547;
204 | background-color: #ffffff;
205 | }
206 | a:hover {
207 | color: #747bff;
208 | }
209 | button {
210 | background-color: #f9f9f9;
211 | }
212 | }
213 |
--------------------------------------------------------------------------------